C++实现二叉排序树
1.定义
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。

2.代码实现
2.1 插入元素:
假设我们要为数组 a[] = {10 , 5 , 15 , 6 , 4 , 16 }构建一个二叉排序树,我们按顺序逐个插入元素。
插入过程是这样的:
- 如果是空树,则创建一个新节点,新节点作为根,因此以元素10构建的节点为该二叉查找树的根。
- 插入5,5比10小,与10的左孩子节点进行比较,10的左孩子节点为空,进行插入。
- 插入15,15比10大,与10的右孩子节点进行比较,10的右孩子节点为空,进行插入。
- 插入6,6比10小,与10的左孩子节点5比较;6比5大,与5的右孩子节点进行比较,5的右孩子为空,进行插入。
- 插入4,4比10小,与10的左孩子节点5比较;4比5小,与5的左孩子节点进行比较,5的左孩子为空,进行插入。
- 插入16,16比10大,与10的右孩子节点15比较;16比15大,与15的右孩子节点进行比较,15的右孩子为空,进行插入。
从这个过程我们可以总结出插入新元素的步骤:
- 寻找元素合适的插入位置:新元素与当前结点进行比较,若值大于当前结点,则从右子树进行寻找;否则从左子树进行寻找.
- 找到插入位置之后,以元素的值构建新节点,插入二叉排序树中
/*插入函数*/
template <typename T>
void BSTree<T>::insert(T key)
{
BSNode<T>* pparent = nullptr;
BSNode<T>* pnode = root; while (pnode != nullptr) //寻找合适的插入位置
{
pparent = pnode;
if (key > pnode->value)
pnode = pnode->rchild;
else if (key < pnode->value)
pnode = pnode->lchild;
else
break;
} pnode = new BSNode<T>(key);
if (pparent == nullptr) //如果是空树
{
root = pnode; //则新节点为根
}
else
{
if (key > pparent->value)
{
pparent->rchild = pnode;//新节点为其父节点的右孩子
}
else
pparent->lchild = pnode;//新节点为其父节点左孩子
}
pnode->parent = pparent; //指明新节点的父节点 };
2.2 删除元素:
删除二叉排序树的某个节点有三种情况:
- 被删除节点同时有左子树与右子树。
- 被删除节点只有左子树或只有右子树。
- 被删除节点没有子树。
对于第一种情况,我们的处理方式是将前驱节点的值保存在当前结点,继而删除前驱节点。
对于第二种情况,我们直接用子树替换被删节点。
对于第三种情况,我们可以直接删除节点。
template <typename T>
void BSTree<T>::remove(BSNode<T>* pnode, T key)
{
if (pnode != nullptr)
{
if (pnode->value == key)
{
BSNode<T>* pdel = nullptr; if (pnode->lchild == nullptr || pnode->rchild == nullptr)
pdel = pnode; //情况二、三:被删节点只有左子树或右子树,或没有孩子
else
pdel = predecessor(pnode); //情况一:被删节点同时有左右子树,则删除该节点的前驱 //此时,被删节点只有一个孩子(或没有孩子).保存该孩子指针
BSNode<T>* pchild = nullptr;
if (pdel->lchild != nullptr)
pchild = pdel->lchild;
else
pchild = pdel->rchild; //让孩子指向被删除节点的父节点
if (pchild != nullptr)
pchild->parent = pdel->parent; //如果要删除的节点是头节点,注意更改root的值
if (pdel->parent == nullptr)
root = pchild; //如果要删除的节点不是头节点,要注意更改它的双亲节点指向新的孩子节点
else if (pdel->parent->lchild == pdel)
{
pdel->parent->lchild = pchild;
}
else
{
pdel->parent->rchild = pchild;
} if (pnode->value != pdel->value)
pnode->value = pdel->value;
delete pdel;
}
//进行递归删除
else if (key > pnode->value)
{
remove(pnode->rchild, key);
}
else remove(pnode->lchild, key);
}
};
2.3 查找指定元素的节点(While循环):
判断当前结点是否为空指针,不是空指针进入
key直接和当前结点value相等,return当前结点
key大于当前结点value,将右子节点赋予当前结点
key小于当前结点value,将左子节点赋予当前结点
直到key等于当前结点或者当前结点为空停止while循环
/*查找指定元素的节点(非递归)*/
template <typename T>
BSNode<T>* BSTree<T>::search_Iterator(T key)
{
BSNode<T> * pnode = root;
while (pnode != nullptr)
{
if (key == pnode->value) //找到
return pnode;
if (key > pnode->value) //关键字比节点值大,在节点右子树查找
pnode = pnode->rchild;
else
pnode = pnode->lchild; //关键字比节点值小,在节点左子树查找
}
return nullptr;
};
2.4 查找指定元素的节点(递归):
逻辑同上,将pnode替换为左或者右子节点,递归调用之
/*查找指定元素的节点(递归)*/
template <typename T>
BSNode<T>* BSTree<T>::search_recursion(T key)
{
return search(root, key);
}; /*private:search()*/
/*递归查找的类内部实现*/
template <typename T>
BSNode<T>* BSTree<T>::search(BSNode<T>* & pnode, T key)
{
if (pnode == nullptr)
return nullptr;
if (pnode->value == key)
return pnode;
//cout << "-->" << pnode->value << endl; //可以输出查找路径
if (key > pnode->value)
return search(pnode->rchild, key);
return search(pnode->lchild, key);
};
2.5 寻找其前驱节点:
前驱和后继结点说明:
对于一棵二叉排序树,中序遍历时刚好可以输出一个非递减的序列。例如中序遍历图九树a:3 4 5 6 10 15 16,则可称:
- 4是5 前驱节点,6是5的后继节点
- 6是10的前驱节点,15是10的后继节点
前驱结点:
- 它有左子树,则左子树的最右结点为其前驱节点
- 它没有左子树,且它本身为右子树,则其父节点为其前驱节点
- 它没有左子树,且它本身为左子树,则它的前驱节点为“第一个拥有右子树的父节点”
判断当前结点左子树是否为空,不为空进入
左孩子赋予当前结点,与情况1对应
判断父节点是否是空指针并且当前结点本身是否是左子树
本身是左子树,进入循环,是第三种情况。不是左子树,是第二种情况
/*寻找其前驱节点*/
/*
一个节点的前驱节点有3种情况:
1. 它有左子树,则左子树最右结点为其前驱节点
2. 它没有左子树,且它本身为右子树,则其父节点为其前驱节点
3. 它没有左子树,且它本身为左子树,则它的前驱节点为“第一个拥有右子树的父节点”
*/
template <typename T>
BSNode<T>* BSTree<T>::predecessor(BSNode<T>* pnode)
{
if (pnode->lchild != nullptr)
{
pnode = pnode->lchild;
while (pnode->rchild != nullptr)
{
pnode = pnode->rchild;
}
return pnode;
} BSNode<T>* pparent = pnode->parent;
while (pparent != nullptr && pparent->lchild == pnode)//如果进入循环,则是第三种情况;否则为第二种情况
{
pnode = pparent;
pparent = pparent->parent;
}
return pparent;
};
2.6 寻找后继结点
- 它有右子树;则其后继节点为其右子树的最左节点
- 它没有右子树,但它本身是一个左孩子,则后继节点为它的双亲
- 它没有右子树,但它本身是一个右孩子,则其后继节点为“具有左孩子的最近父节点”
判断当前结点右子树是否是空指针,不为空则进入
右子树赋予当前结点,当左子树不为空,将左子树赋予当前结点,对应情况1
如果当前结点没有右子树
判断父节点是否是空指针并且当前结点本身是否是右子树
本身是右子树,进入循环,对应情况3
本身不是右子树,不进入循环,对应情况2
/*寻找其后继节点*/
/*
一个点有后继节点的情况:
1. 它有右子树;则其后继节点为其右子树的最左节点
2. 它没有右子树,但它本身是一个左孩子,则后继节点为它的双亲
3. 它没有右子树,但它本身是一个右孩子,则其后继节点为“具有左孩子的最近父节点”
*/
template <typename T>
BSNode<T>* BSTree<T>::successor(BSNode<T>* pnode)
{
if (pnode->rchild != nullptr)
{
pnode = pnode->rchild;
while (pnode->lchild != nullptr)
{
pnode = pnode->lchild;
}
return pnode;
} BSNode<T>* pparent = pnode->parent;
while (pparent != nullptr&& pparent->rchild == pnode)
{
pnode = pparent;
pparent = pparent->parent;
}
return pparent;
};
2.7 寻找最大和最小元素数
这个比较好理解,根据二叉排序树定义,寻找最大就是不停地递归寻找右子树,直到右子树为空结束
寻找最小就是不停地递归寻找左子树,直到左子树为空
/*寻找最小元素*/
template <typename T>
T BSTree<T>::search_minimun()
{
return search_minimun(root);
};
template <typename T>
T BSTree<T>::search_minimun(BSNode<T>* p)
{
if (p->lchild != nullptr)
return search_minimun(p->lchild);
return p->value;
}; /*寻找最大元素*/
template <typename T>
T BSTree<T>::search_maximum()
{
return search_maximum(root);
};
template <typename T>
T BSTree<T>::search_maximum(BSNode<T>*p)
{
if (p->rchild != nullptr)
return search_maximum(p->rchild);
return p->value;
};
参考:https://www.cnblogs.com/QG-whz/p/5168620.html#_label3_2
C++实现二叉排序树的更多相关文章
- 【数据结构】简单谈一谈二分法和二叉排序树BST查找的比较
二分法查找: 『在有序数组的基础上通过折半方法不断缩小查找范围,直至命中或者查询失败.』 二分法的存储要求:要求顺序存储,以便于根据下标随机访问 二分法的时间效率:O(Log(n)) 二分 ...
- 二叉排序树(BST)创建,删除,查找操作
binary search tree,中文翻译为二叉搜索树.二叉查找树或者二叉排序树.简称为BST 一:二叉搜索树的定义 他的定义与树的定义是类似的,也是一个递归的定义: 1.要么是一棵空树 2.如果 ...
- 数据结构图文解析之:树的简介及二叉排序树C++模板实现.
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 二叉树建立,遍历和二叉排序树的判断【c++】
// test.cpp : Defines the entry point for the console application. // #include "stdafx.h" ...
- PAT A 1115. Counting Nodes in a BST (30)【二叉排序树】
题目:二叉排序树,统计最后两层节点个数 思路:数组格式存储,insert建树,dfs遍历 #include<cstdio> #include<iostream> #includ ...
- 二叉排序树(Binary Sort Tree)
参考文章:http://blog.csdn.net/ns_code/article/details/19823463 不过博主的使用第一种方法操作后的树已经不是二叉排序树了,值得深思!! #inclu ...
- HDU 3999 二叉排序树
The order of a Tree Problem Description The shape of a binary search tree is greatly related to the ...
- 二叉排序树(BST)的建立
给一个非递归的吧. /* 已知,二叉树存储结构定义见bstree.h,请编写一个算法函数bstree creatBstree(int a[],int n), 以数组a中的数据作为输入建立一棵二叉排序树 ...
- POJ 2418 各种二叉排序树
题意很明确,统计各个字符串所占总串数的百分比,暴力的话肯定超时,看了书上的题解后发现这题主要是用二叉排序树来做,下面附上n种树的代码. 简单的二叉排序树,不作任何优化(C语言版的): #include ...
- c语言编程之二叉排序树
二叉排序树,又称为二叉查找树.它是一颗空树,或者是具有下面的性质的二叉树: 1.若它的左子树不空,则左子树上所有节点的值均小于它的根结构的值: 2.若它的右子树不空,则右子树上所有节点的值均大于它的根 ...
随机推荐
- maven项目搜索依赖jar包顺序
local_repo > settings_profile_repo > pom_profile_repo > pom_repositories > setti ...
- Python实现简单登陆验证(文件操作)
利用python编写一个简单的登陆验证 代码主要功能: 利用Python实现简单的登陆验证,代码主要有两个部分组成: 第一部分:登陆页面,作用是实现用户名和密码的输入 利用两个输入函数input()来 ...
- MVC中控制器向视图传值的四种方式
MVC中的控制器向视图传值有四种方式分别是 1 ViewDate 2.ViewBag 3.TempDate 4.Model 下面分别介绍四种传值方式 首先先显示出控制器中的代码 using S ...
- “全栈2019”Java第三章:安装开发工具IntelliJ IDEA
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- 苹果笔记本调整 pycharm 字体大小的地方
我想,对于习惯了使用windows版本 或者 乌班图版本 的pycharm 的人而言, mac版本调节字体的地方藏的实在是太坑爹了.
- hadoop1.0.4运行程序出现“Java heap Space”错误
根据虾皮博客中教程,成功搭建了一个12台电脑的Hadoop云平台,而且成功运行了软件自带的wordcount程序,处理10M数据. 但是当程序处理40M时候,却出错了.出错提示“Java Heap S ...
- [Objective-C语言教程]结构体(17)
Objective-C数组可定义包含多个相同类型的数据项的变量类型,但结构体是Objective-C编程中的另一个用户定义数据类型,它可组合不同类型的数据项. 结构体用于表示记录,假设要图书馆中跟踪书 ...
- [Swift实际操作]八、实用进阶-(2)Swift语言中的三种消息传递模式
本文将通过响应按钮的点击事件,来演示Target-Action消息传递机制,该机制主要用于响应用户的界面操作.打开创建的空白项目.然后在左侧的项目导航区,打开视图控制器的代码文件:ViewContro ...
- extjs Tree中避免连续单击会连续请求服务器
应用场景:在项目中我要做一个左边是tree,右边是panel的界面.当我单击tree中的一条记录时,发送请求,并将结果显示在右边的panel中.做完之后发现,如果连续单击就会连续请求两次服务器,毕竟用 ...
- AWS 推出长期支持的 OpenJDK 免费分发版本 —— Amazon Corretto
简评:听说 Oracle JDK 要收费了,Oracle 要限制 Java 的商业或生产用途,针对这个问题,AWS 将会推出 Amazon Corretto. Java 是 AWS 用户使用的最流行的 ...