数据结构---二叉搜索树BST实现
1. 二叉查找树
二叉查找树(Binary Search Tree),也称为二叉搜索树、有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
- 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
- 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点。
2. 节点类
class BSTNode{
public:
int data;
BSTNode *left;
BSTNode *right;
BSTNode(int x):
data(x), left(NULL), right(NULL){}
};
在写代码的过程中发现有的类方法需要经常使用某节点的父节点,所以可以考虑在数据成员中添加父节点 BSTNode* parents ,本文是在BSTree的方法中添加了函数 BSTNode* BSTree::getParents(int value)
3. 二叉搜索树类
class BSTree{
public:
BSTNode *root;
BSTree():
root(NULL){}
~BSTree(){destory(root);}
// 是否为空
bool isEmpty();
// 深度
int depth(BSTNode *&proot);
// 节点数
int size(BSTNode *&proot);
// 叶子节点数
int leafsize(BSTNode *&proot);
// 前序遍历
void preOrder(BSTNode* &pRoot);
// 中序遍历
void inOrder(BSTNode* &pRoot);
// 后序遍历
void postOrder(BSTNode* &pRoot);
// 层序遍历
void levelOrder(BSTNode* &pRoot);
// 查找
bool search(int value);
// 插入
void insert(int value);
// 删除
void remove(int value);
// 寻找前驱节点
BSTNode* predecessor(int value);
// 寻找后继节点
BSTNode* successor(int value);
// 最小值
int minimum();
// 最大值
int maximum();
// 销毁BST
void destory(BSTNode *&proot);
private:
// 获取value节点的地址
BSTNode* getAddr(int value);
// 获取value父节点的地址
BSTNode* getParents(int value);
};
4. 主要方法
对于基本的方法,如深度、节点数、叶子节点数没什么难点;
对于三种遍历方法使用的是经典的递归方法;
对于BST的最大/最小值,主要记住最小值永远在根节点的最左边,最大值永远在根节点的最右边,只需要不停的向最左或最优遍历即可,直到空节点结束(最大最小值也可能是根节点);
BST的难点可能就在节点删除的部分,以下图所示的树为对象,讲一下节点删除:
/*
* 62
* / \
* 58 88
* / / \
* 47 73 99
* / \ /
* 35 51 93
* / \ / \
* 29 37 49 56
* / / \
* 36 48 50
*
*/
被删除的节点可能是一下3种情况之一:
1. 叶子节点 2. 只含有左子树或只含有右子树的节点 3. 同时含有左右子树的节点
细分:
1. 叶子节点
1.1 树只含有一个节点,删除叶子节点
如果树只有一个节点,则该节点即是根节点又是叶节点,删除时需要将root置空
1.2 树含有至少2个节点,删除叶子节点
如图上的 29 36 73等,删除叶子节点对BST没有影响,删除即可,同时需要维护指针;
2. 仅有左或者右子树的节点
2.1 仅有左子树的节点,同时该节点是根节点
2.2 仅有左子树的节点,同时该节点非根节点
2.3 仅有右子树的节点,同时该节点是根节点
2.4 仅有右子树的节点,同时该节点非根节点
上述四种情况只需要将待删节点的左右孩子放到待删节点的位置即可,同时注意是不是需要维护根节点
3. 左右子树都有的节点
首先寻找待删节点的直接前驱,然后用直接前驱代替待删节点。如删除47,47的前驱是37,那么将37节点的数据复制到47节点,释放37,同时将35的右孩子指向36,原47节点的右子树不动。
以上具体细节见完整代码
5. 完整代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std; class BSTNode{
public:
int data;
BSTNode *left;
BSTNode *right;
BSTNode(int x):
data(x), left(NULL), right(NULL){}
}; class BSTree{
public:
BSTNode *root;
BSTree():
root(NULL){}
~BSTree(){destory(root);} // 是否为空
bool isEmpty();
// 深度
int depth(BSTNode *&proot);
// 节点数
int size(BSTNode *&proot);
// 叶子节点数
int leafsize(BSTNode *&proot); // 前序遍历
void preOrder(BSTNode* &pRoot);
// 中序遍历
void inOrder(BSTNode* &pRoot);
// 后序遍历
void postOrder(BSTNode* &pRoot);
// 层序遍历
void levelOrder(BSTNode* &pRoot); // 查找
bool search(int value);
// 插入
void insert(int value);
// 删除
void remove(int value); // 寻找前驱节点
BSTNode* predecessor(int value);
// 寻找后继节点
BSTNode* successor(int value); // 最小值
int minimum();
// 最大值
int maximum(); // 销毁BST
void destory(BSTNode *&proot); private:
// 获取value节点的地址
BSTNode* getAddr(int value);
// 获取value父节点的地址
BSTNode* getParents(int value);
}; bool BSTree::isEmpty(){
return root==NULL;
} int BSTree::depth(BSTNode *&proot){
if(proot == NULL)
return ;
int left = depth(proot->left);
int right = depth(proot->right);
if(left > right)
return left + ;
else
return right + ;
} int BSTree::size(BSTNode *&proot){
if(proot == NULL)
return ;
int left = size(proot->left);
int right = size(proot->right);
return left + right + ;
} int BSTree::leafsize(BSTNode *&proot){
if(proot == NULL)
return ;
if(proot->left == NULL && proot->right == NULL)
return ;
int leftLeaf = leafsize(proot->left);
int rightLeaf = leafsize(proot->right);
return leftLeaf + rightLeaf;
} BSTNode* BSTree::getParents(int value){
if(BSTree::search(value) == true){
BSTNode* pRoot = root;
BSTNode* parents; // 用于存储value节点的父节点
while(pRoot->data!=value){
parents = pRoot;
if(pRoot->data > value)
pRoot = pRoot->left;
else
pRoot = pRoot->right;
}
if(pRoot == root){
//cout<<"the value is root of the tree, NO PARENTS."<<endl;
return NULL;
}
else
return parents;
}
else{
cout<<"the value is not in the tree."<<endl;
return NULL;
}
} BSTNode* BSTree::getAddr(int value){
if(BSTree::search(value) == true){
BSTNode* pRoot = root;
while(pRoot->data!=value){
if(pRoot->data > value)
pRoot = pRoot->left;
else
pRoot = pRoot->right;
}
return pRoot;
}
else{
cout<<"the value is not in the tree."<<endl;
return NULL;
}
} // 若value不在树内或者value没有前驱,返回null,否则,返回前驱节点地址
BSTNode* BSTree::predecessor(int value){
if(!search(value)){
cout<<"the value is not in the tree."<<endl;
return NULL;
}
else if(BSTree::minimum() == value){
cout<<"节点"<<value<<"没有前驱节点"<<endl;
return NULL;
}
else{
BSTNode* pRoot = getAddr(value);// 用于存储value节点的地址
BSTNode* parents = getParents(value); // 用于存储value的父节点地址
// 含左子树的节点
if(pRoot->left != NULL){
BSTNode* pre = pRoot->left;
while(pre->right != NULL){
pre = pre->right;
}
return pre;
}
//没有左子树的节点
else{
if(parents->right == pRoot)
return parents;
else if(parents->left == pRoot){
while(parents->data > value)
parents = getParents(parents->data);
return parents;
}
}
}
} // 若value不在树内或者value没有后继,返回null,否则,返回前后继节点地址
BSTNode* BSTree::successor(int value){
if(!search(value)){
cout<<"the value is not in the tree."<<endl;
return NULL;
}
else if(BSTree::maximum() == value){
cout<<"节点"<<value<<"没有后继节点"<<endl;
return NULL;
}
else{
BSTNode* pRoot = getAddr(value);// 用于存储value节点的地址
BSTNode* parents = getParents(value); // 用于存储value的父节点地址
// 含右子树的节点
if(pRoot->right != NULL){
BSTNode* pre = pRoot->right;
while(pre->left != NULL){
pre = pre->left;
}
return pre;
}
//没有右子树的节点
else{
if(parents->left == pRoot)
return parents;
else if(parents->right == pRoot){
while(parents->data < value)
parents = getParents(parents->data);
return parents;
}
}
}
} int BSTree::minimum(){
BSTNode* proot = root;
while(proot->left != NULL){
proot = proot->left;
}
return proot->data;
} int BSTree::maximum(){
BSTNode* proot = root;
while(proot->right != NULL){
proot = proot->right;
}
return proot->data;
} /*
* 62
* / \
* 58 88
* / / \
* 47 73 99
* / \ /
* 35 51 93
* / \ / \
* 29 37 49 56
* / / \
* 36 48 50
*
* 删除节点的3种情况:
* 1. 叶子节点
* 1.1 树只含有一个节点,删除叶子节点
* 1.2 树含有至少2个节点,删除叶子节点
* 2. 仅有左或者右子树的节点
* 2.1 仅有左子树的节点,删除根节点
* 2.2 仅有左子树的节点,删除非根节点
* 2.3 仅有右子树的节点,删除根节点
* 2.4 仅有右子树的节点,删除非根节点
* 3. 左右子树都有的节点
*
*/ void BSTree::remove(int value){
if(!search(value)){
cout<<"the value is not in the tree. please check."<<endl;
return ;
}
else{
// 查找value节点
BSTNode* pRoot = getAddr(value);// 用于存储value节点的地址
BSTNode* parents = getParents(value); // 用于存储待删除节点的父节点
// 删除value节点
// 1.叶节点
// 1.1 树只含有一个节点
if(pRoot == root && pRoot->left == NULL && pRoot->right == NULL){
root = NULL;
free(pRoot);
}
// 1.2 树含有至少2个节点
else if(pRoot != root && pRoot->left == NULL && pRoot->right == NULL){
// 待删节点是父节点的右孩子
if(parents->right != NULL && parents->right->data == value){
parents->right = NULL;
free(pRoot);
}
// 待删节点是父节点的左孩子
else{
parents->left = NULL;
free(pRoot);
}
}
// 2. 仅有左子树或右子树的节点
// 2.1 仅有左子树,且删除根节点
else if(pRoot == root && pRoot->left != NULL && pRoot->right == NULL){
root = pRoot->left;
free(pRoot);
}
// 2.2 仅有左子树的节点,删除非根节点
else if(pRoot != root && pRoot->left != NULL && pRoot->right == NULL){
// 待删节点是父节点的右孩子
if(parents->right != NULL && parents->right->data == value){
parents->right = pRoot->left;
free(pRoot);
}
// 待删节点是父节点的左孩子
else{
parents->left = pRoot->left;
free(pRoot);
}
}
// 2.3 仅有右子树的节点,删除根节点
else if(pRoot == root && pRoot->left == NULL && pRoot->right != NULL){
root = pRoot->right;
free(pRoot);
}
// 2.4 仅有右子树的节点, 删除非根节点
else if(pRoot != root && pRoot->left == NULL && pRoot->right != NULL){
// 待删节点是父节点的右孩子
if(parents->right != NULL && parents->right->data == value){
parents->right = pRoot->right;
free(pRoot);
}
// 待删节点是父节点的左孩子
else{
parents->left = pRoot->right;
free(pRoot);
}
}
// 3. 左右子树都有的节点
else{
// 寻找待删除节点的直接前驱
BSTNode* pre = predecessor(value);// pre存储直接前驱
pRoot->data = pre->data;// 数据覆盖
// 寻找直接前驱的左/右节点
if(pre->right != NULL){
BSTNode *pRootNext = pRoot->right;
BSTNode *temp = pre->right;
if(pre == pRootNext)
pRoot->right = temp;
else
pRootNext->left = temp;
free(pre);
}
else if(pre->left != NULL){
BSTNode *pRootNext = pRoot->left;
BSTNode *temp = pre->left;
if(pre == pRootNext)
pRoot->left = temp;
else
pRootNext->right = temp;
free(pre);
}
else if(pre->left == NULL && pre->right == NULL){
pRoot->left = NULL;
free(pre);
}
}
}
} bool BSTree::search(int value){
BSTNode* pRoot = root;
while(pRoot!=NULL && pRoot->data!=value){
if(pRoot->data > value)
pRoot = pRoot->left;
else
pRoot = pRoot->right;
}
if(pRoot == NULL)
return false;
else
return true;
} void BSTree::insert(int value){
// value节点已经存在
if(BSTree::search(value) == true){
cout<<"the value "<<value<<" in the tree already."<<endl;
return ;
}
// value节点不存在
else{
BSTNode* pRoot = root;
// 空树
if(pRoot == NULL)
root = new BSTNode(value);
// 非空
else{
BSTNode* temp;
while(pRoot!= NULL && pRoot->data!=value){
temp = pRoot;
if(pRoot->data > value)
pRoot = pRoot->left;
else
pRoot = pRoot->right;
}
pRoot = temp;
if(pRoot->data>value)
pRoot->left = new BSTNode(value);
else
pRoot->right = new BSTNode(value);
}
}
cout<<"the value "<<value<<" is inserted."<<endl;
} void BSTree::preOrder(BSTNode* &pRoot){
if(pRoot == NULL)
return ;
cout<<pRoot->data<<' ';
preOrder(pRoot->left);
preOrder(pRoot->right);
} void BSTree::inOrder(BSTNode* &pRoot){
if(pRoot == NULL)
return ;
inOrder(pRoot->left);
cout<<pRoot->data<<' ';
inOrder(pRoot->right);
} void BSTree::postOrder(BSTNode* &pRoot){
if(pRoot == NULL)
return ;
postOrder(pRoot->left);
postOrder(pRoot->right);
cout<<pRoot->data<<' ';
} void BSTree::levelOrder(BSTNode *&pRoot){
queue<BSTNode*> p;
if(pRoot == NULL)
return ;
p.push(pRoot);
while (!p.empty()){
BSTNode *temp = p.front();
cout<<temp->data<<' ';
p.pop();
if(temp->left)
p.push(temp->left);
if(temp->right)
p.push(temp->right);
}
} void BSTree::destory(BSTNode *&proot){
if (proot== NULL)
return ;
destory(proot->left);
destory(proot->right);
cout<<"free value "<<proot->data<<endl;
free(proot);
proot = NULL;
} int main(int argc, char const *argv[])
{
BSTree tree;
int arr[] = {, , , , ,
, , , , ,
, , , , , };
for(int i=; i<; i++)
tree.insert(arr[i]); cout<<"前序遍历: ";
tree.preOrder(tree.root);
cout<<endl;
cout<<"中序遍历: ";
tree.inOrder(tree.root);
cout<<endl;
cout<<"最小值: "<<tree.minimum()<<endl;
cout<<"最大值: "<<tree.maximum()<<endl; cout<<"深度: "<<tree.depth(tree.root)<<endl;
cout<<"节点数: "<<tree.size(tree.root)<<endl;
cout<<"叶子节点数: "<<tree.leafsize(tree.root)<<endl; int index = ;
BSTNode *pre = tree.predecessor(arr[index]);
if(pre != NULL)
cout<<"节点"<<arr[index]<<"的前驱节点是"<<pre->data<<endl; BSTNode *suc = tree.successor(arr[index]);
if(suc != NULL)
cout<<"节点"<<arr[index]<<"的后继节点是"<<suc->data<<endl; cout<<"删除节点: "<<arr[index]<<endl;
tree.remove(arr[index]); cout<<"前序遍历: ";
tree.preOrder(tree.root);
cout<<endl;
cout<<"中序遍历: ";
tree.inOrder(tree.root);
cout<<endl; tree.destory(tree.root);
return ;
}
6. 运行结果
6.1 测试使用的二叉搜索树
/*
* 62
* / \
* 58 88
* / / \
* 47 73 99
* / \ /
* 35 51 93
* / \ / \
* 29 37 49 56
* / / \
* 36 48 50
*
*/
6.2 运行结果
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
the value is inserted.
前序遍历:
中序遍历:
最小值:
最大值:
深度:
节点数:
叶子节点数:
节点47的前驱节点是37
节点47的后继节点是48
删除节点:
前序遍历:
中序遍历:
free value
free value
free value
free value
free value
free value
free value
free value
free value
free value
free value
free value
free value
free value
free value
[Finished in .1s]
数据结构---二叉搜索树BST实现的更多相关文章
- 数据结构☞二叉搜索树BST
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它可以是一棵空树,也可以是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它 ...
- 数据结构-二叉搜索树(BST binary search tree)
本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/ 二叉搜索树简介 顾名思义,二叉搜索树是以一棵二叉树来组织的,这样的一棵树可以用一个链表数据结构来 ...
- C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解
剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...
- 萌新笔记之二叉搜索树(BST)
前言,以前搞过线段树,二叉树觉得也就那样= =.然后数据结构的课也没怎么听过,然后下周期中考... 本来以为今天英语考完可以好好搞ACM了,然后这个数据结构期中考感觉会丢人,还是好好学习一波. 二叉搜 ...
- 给定一个二叉搜索树(BST),找到树中第 K 小的节点
问题:给定一个二叉搜索树(BST),找到树中第 K 小的节点. 出题人:阿里巴巴出题专家:文景/阿里云 CDN 资深技术专家. 考察点: 1. 基础数据结构的理解和编码能力 2. 递归使用 参考答案 ...
- hdu 3791:二叉搜索树(数据结构,二叉搜索树 BST)
二叉搜索树 Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submiss ...
- 看动画学算法之:二叉搜索树BST
目录 简介 BST的基本性质 BST的构建 BST的搜索 BST的插入 BST的删除 简介 树是类似于链表的数据结构,和链表的线性结构不同的是,树是具有层次结构的非线性的数据结构. 树是由很多个节点组 ...
- 在二叉搜索树(BST)中查找第K个大的结点之非递归实现
一个被广泛使用的面试题: 给定一个二叉搜索树,请找出其中的第K个大的结点. PS:我第一次在面试的时候被问到这个问题而且让我直接在白纸上写的时候,直接蒙圈了,因为没有刷题准备,所以就会有伤害.(面完的 ...
- 二叉搜索树 (BST) 的创建以及遍历
二叉搜索树(Binary Search Tree) : 属于二叉树,其中每个节点都含有一个可以比较的键(如需要可以在键上关联值), 且每个节点的键都大于其左子树中的任意节点而小于右子树的任意节点的键. ...
随机推荐
- ASP.NET和C#的区别/
1..NET是一个平台,一个抽象的平台的概念. .NET平台其本身实现的方式其实还是库,抽象层面上来看是一个平台. 个人理解.NET核心就只是.NET Framework. .NET Framewor ...
- [Codeforces 1037E] Trip
[题目链接] http://codeforces.com/problemset/problem/1037/E [算法] 首先离线 , 将问题倒过来考虑 , 转化为 : 每次删除一条边 , 此时最多有多 ...
- 搜索goog
http://www.tech365.net/share/24.html 64.233.160.132|64.233.168.17|64.233.168.167|64.233.160.98|64.23 ...
- KeepAlived的实现示例
KeepAlived的实现示例 KeepAlived的实现 HA Cluster配置准备: 各节点时间必须同步 ntp(6), chrony(7) 1>在centos6上 ntpdate 172 ...
- sshfs把远程主机的文件系统映射到本地的目录中(转载)
转自:http://www.fwolf.com/blog/post/329 windows之外的世界比想像中要大得多呢,几乎天天都在用ssh,却到今天才知道有sshfs这个好东西,前几天还在为Zend ...
- E20171102-E
segment n. 环节; 部分,段落; [计算机] (字符等的) 分段; [动物学] 节片; distinct adj. 明显的,清楚的; 卓越的,不寻常的; 有区别的; 确切的;
- Rabbitmq笔记一
几个基本概念 Producer 生产者,发送消息的一方,图中左侧的client. Consumer 消费者,接收消息的一方,图中后侧的client. Broker 消息中间件的服务节点,一般一个Rab ...
- 2017西安网络赛B_Coin
样例输入 2 2 1 1 3 1 2 样例输出 500000004 555555560 思路: n重伯努利实验概率分布题. 设q=1-p,p为事件概率. Y为出现偶数次的概率. 所以 Y=1/2*( ...
- arp学习笔记(linux高性能服务编程)
先看看arp的定义吧 现在linux运行这条命令 tcpdump -i eth0:1 -ent '(dst 192.168.5.190 and src 192.168.5.109)or( dst 19 ...
- MySql 1248 - Every derived table must have its own alias
执行一个sql语句,报错:1248 - Every derived table must have its own alias 提示说每一个衍生出来的表,必须要有自己的别名 执行子查询的时候,外层查询 ...