1. 二叉查找树

二叉查找树(Binary Search Tree),也称为二叉搜索树、有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:

  1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点。

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实现的更多相关文章

  1. 数据结构☞二叉搜索树BST

    二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它可以是一棵空树,也可以是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它 ...

  2. 数据结构-二叉搜索树(BST binary search tree)

    本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/ 二叉搜索树简介 顾名思义,二叉搜索树是以一棵二叉树来组织的,这样的一棵树可以用一个链表数据结构来 ...

  3. C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解

    剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...

  4. 萌新笔记之二叉搜索树(BST)

    前言,以前搞过线段树,二叉树觉得也就那样= =.然后数据结构的课也没怎么听过,然后下周期中考... 本来以为今天英语考完可以好好搞ACM了,然后这个数据结构期中考感觉会丢人,还是好好学习一波. 二叉搜 ...

  5. 给定一个二叉搜索树(BST),找到树中第 K 小的节点

    问题:给定一个二叉搜索树(BST),找到树中第 K 小的节点. 出题人:阿里巴巴出题专家:文景/阿里云 CDN 资深技术专家. 考察点: 1. 基础数据结构的理解和编码能力 2.  递归使用 参考答案 ...

  6. hdu 3791:二叉搜索树(数据结构,二叉搜索树 BST)

    二叉搜索树 Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submiss ...

  7. 看动画学算法之:二叉搜索树BST

    目录 简介 BST的基本性质 BST的构建 BST的搜索 BST的插入 BST的删除 简介 树是类似于链表的数据结构,和链表的线性结构不同的是,树是具有层次结构的非线性的数据结构. 树是由很多个节点组 ...

  8. 在二叉搜索树(BST)中查找第K个大的结点之非递归实现

    一个被广泛使用的面试题: 给定一个二叉搜索树,请找出其中的第K个大的结点. PS:我第一次在面试的时候被问到这个问题而且让我直接在白纸上写的时候,直接蒙圈了,因为没有刷题准备,所以就会有伤害.(面完的 ...

  9. 二叉搜索树 (BST) 的创建以及遍历

    二叉搜索树(Binary Search Tree) : 属于二叉树,其中每个节点都含有一个可以比较的键(如需要可以在键上关联值), 且每个节点的键都大于其左子树中的任意节点而小于右子树的任意节点的键. ...

随机推荐

  1. go8---函数function

    package main /* 函数function Go 函数 不支持 嵌套.重载和默认参数. 但支持以下特性: 无需声明原型(C语言在使用函数之前需要声明函数的原型).不定长度变参.多返回值.命名 ...

  2. CPU上电时序详细分析

    首先是RTC电源,这部分电力是永远不关闭的,除非电池(纽扣电池)没电并且没接任何外部电源(比如电池和电源适配器). RTC用以保持机器内部时钟的运转和保证CMOS配置信息在断电的情况下不丢失:其次,在 ...

  3. YTU 2547: Repairing a Road

    2547: Repairing a Road 时间限制: 1 Sec  内存限制: 128 MB 提交: 3  解决: 2 题目描述 You live in a small town with R b ...

  4. zabbix如何添加主机监控

    1,首先,监控的主机安装zabbix客户端.zabbix提供多种监控方式,我们这里监控的主机上边安装agentd守护端进行数据收集并监测. 其中客户端安装我们这里就不介绍了,请参考之前教程里边的客户端 ...

  5. BZOJ_4800_[Ceoi2015]Ice Hockey World Championship_双指针

    BZOJ_4800_[Ceoi2015]Ice Hockey World Championship_双指针 Description 有n个物品,m块钱,给定每个物品的价格,求买物品的方案数. Inpu ...

  6. bzoj 4809: 皇后【dfs】

    爆搜卡线过 并不知道正解是啥 #include<iostream> #include<cstdio> using namespace std; const int N=40; ...

  7. 【BZOJ2525】[Poi2011]Dynamite(二分,树形dp)

    [BZOJ2525][Poi2011]Dynamite Description Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了炸.药,现在需要点燃M个点上的引线引爆所有 ...

  8. P3402 【模板】可持久化并查集

    传送门 //minamoto #include<bits/stdc++.h> using namespace std; #define getc() (p1==p2&&(p ...

  9. ionic2.1.0 --beta3版本新建页面做弹框时遇到的问题

    新建的页面需要在app.module.ts文件中定义.不然制作页面弹出效果是会报错.

  10. Git学习笔记(2)-初探Git

    1.创建版本库 (1)设置Git的配置变量.这些设置会在全局文件(.gitconfig)或系统文件(/etc/gitconfig)中做永久记录 $ git config --global user.n ...