二叉查找树的定义、遍历与查找

定义

二叉查找树(BinaryBinaryBinary SearchSearchSearch TreeTreeTree)或者是一棵空树,或者是具有下列性质的二叉树:

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

上述性质被称为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;
}
查找

对于一个已知的二叉查找树,在其中查找特定的值,方法如下。

  1. 从根节点开始查找;
  2. 如果当前节点的值就是要查找的值,查找成功;
  3. 如果要查找的值小于当前节点的值,在当前节点的左子树中查找该值;
  4. 如果要查找的值大于当前节点的值,在当前节点的右子树中查找该值;
  5. 如果当前节点为空节点,查找失败,二叉查找树中没有要查找的值。

查找的期望时间复杂度为Θ(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;
}

二叉查找树的插入与删除

插入

在二叉查找树中插入元素,要建立在查找的基础上
基本方法是类似于线性表中的二分查找,不断地在树中缩小范围定位,最终找到一个合适的位置插入
具体方法如下所述。

  1. 从根节点开始插入;
  2. 如果要插入的值小于等于当前节点的值,在当前节点的左子树中插入;
  3. 如果要插入的值大于当前节点的值,在当前节点的右子树中插入;
  4. 如果当前节点为空节点,在此建立新的节点,该节点的值为要插入的值,左右子树为空,插入成功。

对于相同的元素,一种方法我们规定把它插入左边,另一种方法是我们在节点上再加一个域,记录重复节点的个数
上述方法为前者
插入的期望时间复杂度为Θ(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;
}
删除

二叉查找树的删除稍有些复杂,要分三种情况分别讨论
基本方法是要先在二叉查找树中找到要删除的节点的位置,然后根据节点分以下情况:

  1. 情况一,该节点是叶节点(没有非空子节点的节点),直接把节点删除即可。
  2. 情况二,该节点是链节点(只有一个非空子节点的节点),为了删除这个节点而不影响它的子树,需要把它的子节点代替它的位置,然后把它删除。如图222所示,删除节点222时,需要把它的左子节点代替它的位置。
  3. 情况三,该节点有两个非空子节点。由于情况比较复杂,一般的策略是用它右子树的最小值来代替它,然后把它删除。如图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&gt;=1000)N^2(N&gt;=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的讲解,有兴趣的同学可以来这里看一下——传送门

二叉查找树——清华大学计算机系 郭家宝相关推荐

  1. Treap图文详解、效率分析与拓展应用——清华大学计算机系 郭家宝

    先给出我自己的一份Treap的代码--传送门 一.什么是 Treap Treap=Tree+HeapTreap=Tree+HeapTreap=Tree+Heap TreapTreapTreap是一种平 ...

  2. 清华大学 计算机系 尹霞,轮椅上的清华博士毕业了,刷屏的还有她......

    近日 清华大学计算机系 2021年毕业典礼上 一位特殊的母亲 引发网友关注 "她几乎走遍了计算机系大部分教室 也跟所有的老师认识相熟 今天我虽不能授她一个学位 但她却应得到我们全系师生的尊重 ...

  3. 清华大学 计算机系 尹霞,轮椅上的清华博士毕业了,刷屏的还有她

    近日 清华大学计算机系2021年毕业典礼上 一位特殊的母亲 引发网友关注 "她几乎走遍了计算机系大部分教室 也跟所有的老师认识相熟 今天我虽不能授她一个学位 但她却应得到我们全系师生的尊重与 ...

  4. 清华大学 计算机系 尹霞,轮椅上的清华博士毕业了,刷屏的还有她 .

    近日 清华大学计算机系 2021 年毕业典礼上 一位特殊的母亲 引发网友关注 " 她几乎走遍了计算机系大部分教室 也跟所有的老师认识相熟 今天我虽不能授她一个学位 但她却应得到我们全系师生的 ...

  5. 清华大学计算机64班,清华大学计算机系的论比文评价.ppt

    清华大学计算机系的论比文评价 提纲 计算机领域论文评价的复杂性 会议论文的重要性 论文价值的主客观度量 客观指标:引用(影响引子),录用率等 主观指标:会议与期刊列表等 一种综合的评价方法 计算机领域 ...

  6. 清华大学计算机系网络教学视频31门计算机课程

    原文:http://www.cnblogs.com/chenhong/archive/2008/07/28/1254915.html 清华大学计算机系网络教学视频31门计算机课程 本科课程 微型计算机 ...

  7. 清华大学计算机系人机交互,喻 纯 - 清华大学 - 《自然人机交互中的智能输入》(47页)-原创力文档...

    智源论坛 Live | 青年科学家线上报告会 自然人机交互的智能输入 喻纯,清华计算机系 2020.2.12 报告大纲 • 个人情况 • 已有研究基础 • 拟研究内容 个人情况 工作经历 2016.1 ...

  8. 清华计算机知识工程怎么样,张民(muslv)清华大学计算机系知识工程组 硕士清华大学.ppt...

    张民(muslv)清华大学计算机系知识工程组 硕士清华大学 内容 为什么引入J2EE? 什么是J2EE? J2EE的组成 EJB-J2EE的基石 EJB的容器和服务器 EJB的分类 会话bean 实体 ...

  9. 清华大学计算机系71班张晨,“神仙打架”要来了!网友:又到了凡人围观的时刻...

    毛烁源 车辆学院 星星之火,可以燎原 男,汽71班,前三年推研成绩年级1/42,入选"星火计划"第十三期,获四项专利授权证书(两项为第一发明人).曾任汽71班学习委员,现任行健书院 ...

最新文章

  1. 【OpenCV3】阈值化操作——cv::threshold()与cv::adaptiveThreshold()详解
  2. 将yolo标注转换为tensorflow_yolov3标注生成train.txt和test.txt同时做数据清洗
  3. 初学者python编辑器用geany可以吗_Lubuntu下小巧好用的Python编辑工具Geany
  4. 字符串hash(一)
  5. EXCEL单元格内的姓名对齐
  6. [转].net中Cache的应用
  7. JAVA项目开发团队分配
  8. 【Scratch案例实操】scratch我们爱编程 scratch编程案例教学 scratch创意编程 少儿编程教案
  9. Excel怎么对比两个表格数据
  10. 开源纯净版u盘安装工具rufus
  11. Linux 中的rsh,ssh
  12. 汇编语言中xor指令_这个汇编代码有什么作用? (TEST,XOR,JNZ)
  13. Alibaba内部Java技术成长笔记,业界良心,程序员最爱
  14. 学习四旋翼(三):DMP姿态解算和串级PID控制姿态
  15. Web前端开发技术:Vue开发基础(1)
  16. es java api 获取总数_es 获取总数的几种方式
  17. linux的资源管理器关进程,RHCSA 系列(五): RHEL7 中的进程管理:开机,关机
  18. 计算机excel2010操作题,计算机应用基础Excel2010综合测试操作步骤参考自测题步骤...
  19. 产品管理服务--数据库设计
  20. Vue项目自动部署之一、阿里云Linux服务器、域名购买和使用

热门文章

  1. [BYR]找什么样的工作?——从找工作中的种种怪象说开去
  2. 计算机ata证书的定义及用处介绍
  3. 网络安全事件层出不穷,是因为国家、组织还是个人?
  4. implode()函数和explode()函数
  5. 双十一买了吗?来看物联网如何助力快递物流
  6. 【转】评论:诺基亚缺乏“谎言” 苹果因此得胜
  7. ultraedit反编译c语言,UltraEdit怎么反编译
  8. props接受参数配置
  9. 漂亮、免费的CSS模板
  10. Paddle框架理解:模型状态、动态图与静态图、paddle.nn与paddle.nn.functional异同