二叉查找树——清华大学计算机系 郭家宝
二叉查找树的定义、遍历与查找
定义
二叉查找树(BinaryBinaryBinary SearchSearchSearch TreeTreeTree)或者是一棵空树,或者是具有下列性质的二叉树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉查找树。
上述性质被称为BSTBSTBST性质
可以看出,二叉查找树是递归定义的
如图111是一个二叉查找树。
下述代码给出了一个BSTBSTBST节点的定义。
struct BST_Node {BST_Node *left, *right;//节点的左右子树的指针int value; //节点的值
};
遍历
对于一个已知的二叉查找树,从小到大输出其节点的值,只需对其进行二叉树的中序遍历,即递归地先输出其左子树,再输出其本身,然后输出其右子树
遍历的时间复杂度为Θ(N)Θ(N)Θ(N)
下述代码为把一个以rootrootroot为根的BSTBSTBST所有节点的值从小到大输出到标准输出流。
BST_Node *root;
void BST_Print(BST_Node *P) {if (P) {BST_Print(P->left);printf(“%d\n”, P->value);BST_Print(P->right);}
}
int main() {BST_Print(root);return 0;
}
查找
对于一个已知的二叉查找树,在其中查找特定的值,方法如下。
- 从根节点开始查找;
- 如果当前节点的值就是要查找的值,查找成功;
- 如果要查找的值小于当前节点的值,在当前节点的左子树中查找该值;
- 如果要查找的值大于当前节点的值,在当前节点的右子树中查找该值;
- 如果当前节点为空节点,查找失败,二叉查找树中没有要查找的值。
查找的期望时间复杂度为Θ(logN)Θ(logN)Θ(logN)
下述代码为在一个已知的二叉查找树中查找值555。
BST_Node *root;
BST_Node *BST_Find(BST_Node *P, int value) {if (!P) return 0; //查找失败if (P->value == value) return P; //查找成功else if (value < P->value) return BST_Find(P->left, value); //在左子树中查找else return BST_Find(P->right, value); //在右子树中查找
}
int main() {BST_Node *result;result = BST_Find(root, 5);//在BST中查找值为5的节点if (result) printf("Found!");else printf("Not Found!");return 0;
}
二叉查找树的插入与删除
插入
在二叉查找树中插入元素,要建立在查找的基础上
基本方法是类似于线性表中的二分查找,不断地在树中缩小范围定位,最终找到一个合适的位置插入
具体方法如下所述。
- 从根节点开始插入;
- 如果要插入的值小于等于当前节点的值,在当前节点的左子树中插入;
- 如果要插入的值大于当前节点的值,在当前节点的右子树中插入;
- 如果当前节点为空节点,在此建立新的节点,该节点的值为要插入的值,左右子树为空,插入成功。
对于相同的元素,一种方法我们规定把它插入左边,另一种方法是我们在节点上再加一个域,记录重复节点的个数
上述方法为前者
插入的期望时间复杂度为Θ(logN)Θ(logN)Θ(logN)。
下述代码为在一个二叉查找树中插入值555。
BST_Node *root;
BST_Node *BST_Insert(BST_Node *&P,int value) {//节点指针要传递引用if (!P) {P = new BST_Node; //插入成功P->value = value;}else if (value <= value) return BST_Insert(P->left, value); //在左子树中插入else return BST_Insert(P->right, value); //在右子树中插入
}
int main() {BST_Insert(root, 5);//在 BST 中插入值 5return 0;
}
删除
二叉查找树的删除稍有些复杂,要分三种情况分别讨论
基本方法是要先在二叉查找树中找到要删除的节点的位置,然后根据节点分以下情况:
- 情况一,该节点是叶节点(没有非空子节点的节点),直接把节点删除即可。
- 情况二,该节点是链节点(只有一个非空子节点的节点),为了删除这个节点而不影响它的子树,需要把它的子节点代替它的位置,然后把它删除。如图222所示,删除节点222时,需要把它的左子节点代替它的位置。
- 情况三,该节点有两个非空子节点。由于情况比较复杂,一般的策略是用它右子树的最小值来代替它,然后把它删除。如图333所示,删除节点222时,在它的右子树中找到最小的节点333,该节点一定为待删除节点的后继。删除节点333(它可能是叶节点或者链节点),然后把节点222的值改为333。
实际上在实现的时候,情况一和情况二是可以一样对待的,因为用叶节点的子节点代替它本身,就是用空节点代替了它,等同于删除
对待情况三除了可以用后继代替本身以外,我们还可以使用它的前驱(左子树的最大值)代替它本身
这就牵涉到了查找最小值的问题,基本方法就是从子树的根节点开始,如果左子节点不为空,那么就访问左子节点,直到左子节点为空,当前节点就是该子树的最小值节点,删除它只需用它的右子节点代替它本身。
下述代码是在一个给定的二叉查找树中删除值222。
BST_Node *root;
int Find_DeleteMin(BST_Node *&P) {//返回子树的最小值并删除 节点指针要传递引用if (!P->left) {//如果已经没有左子节点,删除它BST_Node *t = P;int r = P->value;P = P->right;delete t;return r;}else return Find_DeleteMin(P->left); //如果还有左子节点,访问左子节点
}
void BST_Delete(BST_Node *&P, int value)//节点指针要传递引用
{if (!P) return ; //查找失败,BST 中不存在要删除的节点if (P->value == value) {//查找成功,对其删除if (P->left and P->right) P->value = Find_DeleteMin(P->right);else {BST_Node *t = P;if (P->left) P = P->left;else P = P->right;delete t;}}else if (value < P->value) BST_Delete(P->left, value); //在左子树中查找else BST_Delete(P->right, value); //在右子树中查找
}
int main() {BST_Delete(root, 2);//在 BST 中删除值 2return 0;
}
二叉查找树的平衡性问题讨论
二叉查找树的效果究竟如何?
事实上,随机的进行N2(N>=1000)N^2(N>=1000)N2(N>=1000)次插入和删除之后,二叉查找树会趋向于向左偏沉
为什么会出现这种情况,原因是在于删除时,我们总是选择将待删除节点的后继代替它本身
这样就会造成总是右边的节点数目减少,以至于树向左偏沉
已经被证明,随机插入或删除N2N^2N2次以后,树的期望深度为Θ(N12)Θ(N^{\frac{1}{2}})Θ(N21)
我们可以在删除时随机地选择用前驱还是后继代替本身,以消除向一边偏沉的问题
这种神奇地做法消除了偏沉的不平衡,效果十分明显
对待随机的数据二叉查找树已经做得很不错了,但是如果有像这样6,5,4,3,2,16,5,4,3,2,16,5,4,3,2,1有序的数据插入树中时,会有什么后果出现?
如图444
二叉查找树退化成为了一条链
这个时候,无论是查找、插入还是删除,都退化成了Θ(N)Θ(N)Θ(N)的时间
事实上,在实际的应用中,这种情况会经常出现,而简单的二叉查找树却没有办法变得更快
我们需要使二叉查找树变得尽量平衡,才能保证各种操作在Θ(logN)Θ(logN)Θ(logN)的期望时间内完成,于是各种自动平衡二叉查找树(Self−BalancingSelf-BalancingSelf−Balancing BinaryBinaryBinary SearchSearchSearch TreeTreeTree)因而诞生
在常见的自动平衡二叉查找树(以下简称平衡树)中,有近乎完美平衡的AVLAVLAVL树(Adelson−VelskiiAdelson-VelskiiAdelson−Velskii & LandisLandisLandis TreeTreeTree),红黑树(RedRedRed BlackBlackBlack TreeTreeTree)和SBTSBTSBT(SizeSizeSize BalancedBalancedBalanced TreeTreeTree)等,以及期望平衡的伸展树(SplaySplaySplay TreeTreeTree)和TreapTreapTreap(TreeTreeTree & HeapHeapHeap)等数据结构。
TreapTreapTreap具有可观的平衡性,且最易于编码调试等特点,因此在信息学竞赛中被广泛地使用。
相应的,这里还有关于TreapTreapTreap的讲解,有兴趣的同学可以来这里看一下——传送门
二叉查找树——清华大学计算机系 郭家宝相关推荐
- Treap图文详解、效率分析与拓展应用——清华大学计算机系 郭家宝
先给出我自己的一份Treap的代码--传送门 一.什么是 Treap Treap=Tree+HeapTreap=Tree+HeapTreap=Tree+Heap TreapTreapTreap是一种平 ...
- 清华大学 计算机系 尹霞,轮椅上的清华博士毕业了,刷屏的还有她......
近日 清华大学计算机系 2021年毕业典礼上 一位特殊的母亲 引发网友关注 "她几乎走遍了计算机系大部分教室 也跟所有的老师认识相熟 今天我虽不能授她一个学位 但她却应得到我们全系师生的尊重 ...
- 清华大学 计算机系 尹霞,轮椅上的清华博士毕业了,刷屏的还有她
近日 清华大学计算机系2021年毕业典礼上 一位特殊的母亲 引发网友关注 "她几乎走遍了计算机系大部分教室 也跟所有的老师认识相熟 今天我虽不能授她一个学位 但她却应得到我们全系师生的尊重与 ...
- 清华大学 计算机系 尹霞,轮椅上的清华博士毕业了,刷屏的还有她 .
近日 清华大学计算机系 2021 年毕业典礼上 一位特殊的母亲 引发网友关注 " 她几乎走遍了计算机系大部分教室 也跟所有的老师认识相熟 今天我虽不能授她一个学位 但她却应得到我们全系师生的 ...
- 清华大学计算机64班,清华大学计算机系的论比文评价.ppt
清华大学计算机系的论比文评价 提纲 计算机领域论文评价的复杂性 会议论文的重要性 论文价值的主客观度量 客观指标:引用(影响引子),录用率等 主观指标:会议与期刊列表等 一种综合的评价方法 计算机领域 ...
- 清华大学计算机系网络教学视频31门计算机课程
原文:http://www.cnblogs.com/chenhong/archive/2008/07/28/1254915.html 清华大学计算机系网络教学视频31门计算机课程 本科课程 微型计算机 ...
- 清华大学计算机系人机交互,喻 纯 - 清华大学 - 《自然人机交互中的智能输入》(47页)-原创力文档...
智源论坛 Live | 青年科学家线上报告会 自然人机交互的智能输入 喻纯,清华计算机系 2020.2.12 报告大纲 • 个人情况 • 已有研究基础 • 拟研究内容 个人情况 工作经历 2016.1 ...
- 清华计算机知识工程怎么样,张民(muslv)清华大学计算机系知识工程组 硕士清华大学.ppt...
张民(muslv)清华大学计算机系知识工程组 硕士清华大学 内容 为什么引入J2EE? 什么是J2EE? J2EE的组成 EJB-J2EE的基石 EJB的容器和服务器 EJB的分类 会话bean 实体 ...
- 清华大学计算机系71班张晨,“神仙打架”要来了!网友:又到了凡人围观的时刻...
毛烁源 车辆学院 星星之火,可以燎原 男,汽71班,前三年推研成绩年级1/42,入选"星火计划"第十三期,获四项专利授权证书(两项为第一发明人).曾任汽71班学习委员,现任行健书院 ...
最新文章
- 【OpenCV3】阈值化操作——cv::threshold()与cv::adaptiveThreshold()详解
- 将yolo标注转换为tensorflow_yolov3标注生成train.txt和test.txt同时做数据清洗
- 初学者python编辑器用geany可以吗_Lubuntu下小巧好用的Python编辑工具Geany
- 字符串hash(一)
- EXCEL单元格内的姓名对齐
- [转].net中Cache的应用
- JAVA项目开发团队分配
- 【Scratch案例实操】scratch我们爱编程 scratch编程案例教学 scratch创意编程 少儿编程教案
- Excel怎么对比两个表格数据
- 开源纯净版u盘安装工具rufus
- Linux 中的rsh,ssh
- 汇编语言中xor指令_这个汇编代码有什么作用? (TEST,XOR,JNZ)
- Alibaba内部Java技术成长笔记,业界良心,程序员最爱
- 学习四旋翼(三):DMP姿态解算和串级PID控制姿态
- Web前端开发技术:Vue开发基础(1)
- es java api 获取总数_es 获取总数的几种方式
- linux的资源管理器关进程,RHCSA 系列(五): RHEL7 中的进程管理:开机,关机
- 计算机excel2010操作题,计算机应用基础Excel2010综合测试操作步骤参考自测题步骤...
- 产品管理服务--数据库设计
- Vue项目自动部署之一、阿里云Linux服务器、域名购买和使用
热门文章
- [BYR]找什么样的工作?——从找工作中的种种怪象说开去
- 计算机ata证书的定义及用处介绍
- 网络安全事件层出不穷,是因为国家、组织还是个人?
- implode()函数和explode()函数
- 双十一买了吗?来看物联网如何助力快递物流
- 【转】评论:诺基亚缺乏“谎言” 苹果因此得胜
- ultraedit反编译c语言,UltraEdit怎么反编译
- props接受参数配置
- 漂亮、免费的CSS模板
- Paddle框架理解:模型状态、动态图与静态图、paddle.nn与paddle.nn.functional异同