红黑树(更高级的二叉查找树)
目录
介绍及性质
红黑树的基本定义
黑高度
时间复杂度
接近于“平衡”操作
红黑树的旋转
红黑树中插入新结点
红黑树中删除结点
红黑树与AVL树的区别
介绍及性质
- 红黑树(R-B TREE,全称:Red-Black Tree),本身是一棵二叉查找树,在其基础上附加了两个要求:
- 1. 树中的每个结点增加了一个用于存储颜色的标志域;
- 2. 树中没有一条路径比其他任何路径长出两倍,整棵树要接近于“平衡”的状态
- 这里所指的路径,指的是从任何一个结点开始,一直到其子孙的叶子结点的长度;
- 接近于平衡:红黑树并不是平衡二叉树,只是由于对各路径的长度之差有限制,所以近似于平衡的状态
- 红黑树对于结点的颜色设置不是任意的,需满足以下性质的二叉查找树才是红黑树:
- 树中的每个结点颜色不是红的,就是黑的;
- 根结点的颜色是黑的;
- 所有为 nil 的叶子结点的颜色是黑的;(注意:叶子结点说的只是为空(nil 或 NULL)的叶子结点!)
- 如果此结点是红的,那么它的两个孩子结点全部都是黑的;
- 对于每个结点,从该结点到到该结点的所有子孙结点的所有路径上包含有相同数目的黑结点;
- 哪些性质反映了红黑树结构的平衡?
- 性质5 反映了红黑树结构的平衡
- 它确保从任意一个节点出发到其叶子节点的所有路径中,最长路径长度也不会超过最短路径长度的两倍;因而,红黑树是相对接近平衡的二叉树
- 而且性质5 明显指出每个节点的左右子树中黑节点的层数是相等的,因此红黑树的黑节点是完美平衡的
红黑树的基本定义
黑高度
- 注意:图中每个结点附带一个整形数值,表示的是此结点的黑高度(从该结点到其子孙结点中包含的黑结点数,用 bh(x) 表示(x 表示此结点))
- nil 的黑高度为 0,颜色为黑色(在编程时为节省空间,所有的 nil 共用一个存储空间)
- 在计算黑高度时,也看做是一个黑结点
- 红黑树中每个结点都有各自的黑高度,整棵树也有自己的黑高度,即为根结点的黑高度,例如图中的红黑树的黑高度为 3
时间复杂度
- 对于一棵具有 n 个结点的红黑树,树的高度至多为:2lg(n+1)
- 由此可推出红黑树进行查找操作时的时间复杂度为 O(lgn),因为对于高度为 h 的二叉查找树的运行时间为 O(h),而包含有 n 个结点的红黑树本身就是最高为 lgn(简化之后)的查找树(h=lgn),所以红黑树的时间复杂度为 O(lgn)
接近于“平衡”操作
- 红黑树本身作为一棵二叉查找树,所以其任务就是用于动态表中数据的插入和删除的操作
- 在进行该操作时,避免不了会破坏红黑树的结构,此时就需要进行适当的调整,使其重新成为一棵红黑树,可以从两个方面着手对树进行调整:
- 调整树中某些结点的指针结构;
- 调整树中某些结点的颜色;
红黑树的旋转
- 当使用红黑树进行插入或者删除结点的操作时,可能会破坏红黑树的 5 条性质,从而变成了一棵普通树
- 此时就可以通过对树中的某些子树进行旋转,从而使整棵树重新变为一棵红黑树
- 旋转操作分为左旋和右旋
- 左旋:如图所示,左旋时 y 结点变为该部分子树的根结点,同时 x 结点(连同其左子树 a)移动至 y 结点的左孩子
- 若 y 结点有左孩子 b,由于 x 结点需占用其位置,所以调整至 x 结点的右孩子处
- 右旋:如图所示,同左旋是同样的道理,x 结点变为根结点,同时 y 结点连同其右子树 c 作为 x 结点的右子树,原 x 结点的右子树 b 变为 y 结点的左子树
红黑树中插入新结点
- 为什么新插入的节点颜色是红的?
- 将新插入的节点着色为红色,不会违背特性5
- 少违背一条特性,就意味着我们需要处理的情况越少
- 当创建一个红黑树或者向已有红黑树中插入新的数据时,只需要按部就班地执行以下 3 步:
- 由于红黑树本身是一棵二叉查找树,所以在插入新的结点时,完全按照二叉查找树插入结点的方法,找到新结点插入的位置;
- 将新插入的结点结点初始化,颜色设置为红色后插入到指定位置;(将新结点初始化为红色插入后,不会破坏红黑树第 5 条的性质)
- 由于插入新的结点,可能会破坏红黑树第 4 条的性质(若其父结点颜色为红色,就破坏了红黑树的性质),此时需要调整二叉查找树,想办法通过旋转以及修改树中结点的颜色,使其重新成为红黑树!
- 插入结点的第 1 步和第 2 步都非常简单,关键在于最后一步对树的调整!
- 在红黑树中插入结点时,根据插入位置的不同可分为以下 3 种情况:
- 1. 插入位置为整棵树的树根;处理办法:只需要将插入结点的颜色改为黑色即可
- 2. 插入位置的双亲结点的颜色为黑色;处理方法:此种情况不需要做任何工作,新插入的颜色为红色的结点不会破坏红黑树的性质
- 3. 插入位置的双亲结点的颜色为红色;处理方法:由于插入结点颜色为红色,其双亲结点也为红色,破坏了红黑树第 4 条性质,此时需要结合其祖父结点和祖父结点的另一个孩子结点(父结点的兄弟结点,此处称为“叔叔结点”)的状态,分为 3 种情况讨论:
- 当前结点的父节点是红色,且“叔叔结点”也是红色:破坏了红黑树的第 4 条性质,解决方案为:将父结点颜色改为黑色;将叔叔结点颜色改为黑色;将祖父结点颜色改为红色;下一步将祖父结点认做当前结点,继续判断,处理结果如下图所示
- 分析:此种情况下,由于父结点和当前结点颜色都是红色,所以为了不产生冲突,将父结点的颜色改为黑色
- 但是虽避免了破坏第 4 条,但是却导致该条路径上的黑高度增加了 1 ,破坏了第 5 条性质
- 但是在将祖父结点颜色改为红色、叔叔结点颜色改为黑色后,该部分子树没有破坏第 5 条性质
- 但是由于将祖父结点的颜色改变,还需判断是否破坏了上层树的结构,所以需要将祖父结点看做当前结点,继续判断
- 当前结点的父结点颜色为红色,叔叔结点颜色为黑色,且当前结点是父结点的右孩子;解决方案:将父结点作为当前结点做左旋操作
- 提示:在进行以父结点为当前结点的左旋操作后,此种情况就转变成了第 3 种情况,处理过程跟第 3 种情况同步进行
- 当前结点的父结点颜色为红色,叔叔结点颜色为黑色,且当前结点是父结点的左孩子;解决方案:将父结点颜色改为黑色,祖父结点颜色改为红色,从祖父结点处进行右旋处理;如下图所示:
- 分析:在此种情况下,由于当前结点 F 和父结点 S 颜色都为红色,违背了红黑树的性质 4,此时可以将 S 颜色改为黑色,有违反了性质 5,因为所有通过 S 的路径其黑高度都增加了 1 ,所以需要将其祖父结点颜色设为红色后紧接一个右旋,这样这部分子树有成为了红黑树(上图中的有图虽看似不是红黑树,但是只是整棵树的一部分,以 S 为根结点的子树一定是一棵红黑树)
- 当前结点的父节点是红色,且“叔叔结点”也是红色:破坏了红黑树的第 4 条性质,解决方案为:将父结点颜色改为黑色;将叔叔结点颜色改为黑色;将祖父结点颜色改为红色;下一步将祖父结点认做当前结点,继续判断,处理结果如下图所示
- 内部接口 -- insert(node)的作用是将"node"节点插入到红黑树中
- 外部接口 -- insert(key)的作用是将"key"添加到红黑树中
红黑树中删除结点
- 在红黑树中删除结点,思路更简单,只需要完成 2 步操作:
- 1. 将红黑树按照二叉查找树删除结点的方法删除指定结点;
- 2. 重新调整删除结点后的树,使之重新成为红黑树;(还是通过旋转和重新着色的方式进行调整)
- 在二叉查找树删除结点时,分为 3 种情况:
- 若该删除结点本身是叶子结点,则可以直接删除;
- 若只有一个孩子结点(左孩子或者右孩子),则直接让其孩子结点顶替该删除结点;
- 若有两个孩子结点,则找到该结点的右子树中值最小的叶子结点来顶替该结点,然后删除这个值最小的叶子结点
- 以上三种情况最终都需要删除某个结点,此时需要判断删除该结点是否会破坏红黑树的性质,判断的依据是:
- 1. 如果删除结点的颜色为红色,则不会破坏;
- 2. 如果删除结点的颜色为黑色,则肯定会破坏红黑树的第 5 条性质,此时就需要对树进行调整,调整方案分 4 种情况讨论:
- 删除结点的兄弟结点颜色是红色,调整措施为:将兄弟结点颜色改为黑色,父亲结点改为红色,以父亲结点来进行左旋操作,同时更新删除结点的兄弟结点(左旋后兄弟结点发生了变化),如下图所示:
- 删除结点的兄弟结点及其孩子全部都是黑色的,调整措施为:将删除结点的兄弟结点设为红色,同时设置删除结点的父结点标记为新的结点,继续判断;
- 删除结点的兄弟结点是黑色,其左孩子是红色,右孩子是黑色。调整措施为:将兄弟结点设为红色,兄弟结点的左孩子结点设为黑色,以兄弟结点为准进行右旋操作,最终更新删除结点的兄弟结点;
- 删除结点的兄弟结点是黑色,其右孩子是红色(左孩子不管是什么颜色),调整措施为:将删除结点的父结点的颜色赋值给其兄弟结点,然后再设置父结点颜色为黑色,兄弟结点的右孩子结点为黑色,根据其父结点做左旋操作,最后设置替换删除结点的结点为根结点;
- 红黑树,虽隶属于二叉查找树,但是二叉查找树的时间复杂度会受到其树深度的影响,而红黑树可以保证在最坏情况下的时间复杂度仍为 O(lgn)
- 当数据量多到一定程度时,使用红黑树比二叉查找树的效率要高
- 内部接口 -- remove(node)的作用是将"node"节点插入到红黑树中
- 外部接口 -- remove(key)删除红黑树中键值为key的节点
红黑树与AVL树的区别
- 1---为什么红黑树比 AVL 树更受欢迎?
- 红黑树的平衡条件相对宽松,因此在红黑树中插入与删除结点所需的旋转操作相对更少,结点增删操作相比 AVL 树的效率更高
- 2---和红黑树相比,AVL树是严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过1);不管是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时的,由此可以知道AVL树适合用于插入与删除次数比较少,但查找多的情况
- 3---AVL树追求绝对平衡,条件比较苛刻,实现起来比较麻烦,每次插入新节点之后需要旋转的次数不能预知
- 4---由于维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应用不多,更多的地方是用追求局部而不是非常严格整体平衡的红黑树;当然,如果应用场景中对插入、删除不频繁,只是对查找要求较高,那么AVL还是较优于红黑树
- 5---相较红黑树AVL树查找性能更快
- 6---红黑树放弃了追求完全平衡,而是追求大致平衡,在与AVL树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,维持平衡的时间消耗较少,实现起来也更为简单
- 7---相对于要求严格平衡的AVL树来说,它的旋转次数少,对于插入、删除操作较多的情况下,选择红黑树
- 8---红黑树的查询性能略微逊色于AVL树,因为其比AVL树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的AVL树最多多一次比较,但是,红黑树在插入和删除上优于AVL树,AVL树每次插入删除会进行大量的平衡度计算,而红黑树为了维持红黑性质所做的红黑变换和旋转的开销,相较于AVL树为了维持平衡的开销要小得多
红黑树(更高级的二叉查找树)相关推荐
- 哈希表的查找比红黑树更快吗?
这个主要取决于键的类型,因为哈希表需要考虑hash函数和operate==,而红黑树需要考虑operate<.这其中速度取决于hash函数与operate<的计算成本.一般情况下,两者的成 ...
- 带你手撸红黑树,高级Java开发必看
Kubernetes简介 Kubernetes(简称K8S,K和S之间有8个字母)是用于自动部署,扩展和管理容器化应用程序的开源系统.它将组成应用程序的容器组合成逻辑单元,以便于管理和服务发现.Kub ...
- 从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树...
参考:自平衡二叉查找树 ,红黑树, 算法:理解红黑树 (英文pdf:红黑树) 目录 自平衡二叉树介绍 avl树 2-3树 LLRBT(Left-leaning red-black tree左倾红黑树 ...
- 树 - (二叉查找树,红黑树,B树)- 红黑树
虽是读书笔记,但是如转载请注明出处 http://segmentfault.com/blog/exploring/ .. 拒绝伸手复制党 关于二叉树的基本知识,可以参见:Java 实现基本数据结构 2 ...
- 拉链法导致的链表过深问题为什么不用二叉查找树代替,而选择红黑树?为什么不一直使用红黑树?
之所以选择红黑树是为了解决二叉查找树的缺陷,二叉查找树在特殊情况下会变成一条线性结构(这就跟原来使用链表结构一样了,造成很深的问题),遍历查找会非常慢. 而红黑树在插入新数据后可能需要通过左旋,右旋. ...
- 二叉查找树与红黑树原理和程序全面介绍
转载请注明出处 http://blog.csdn.net/yankai0219/article/details/8273542 学习方法:我主要是参考算法导论以及Nginx中rbtree.h和rbtr ...
- 面试之必掌握知识点:红黑树(一)
面试之必掌握知识点:红黑树(一) 现如今,国内大厂的面试是卷之又卷,像红黑树这种高级平衡树算法也经常会在面试中被问起,很多同学对红黑树一直保持一知半解的状态,为了能在面试中脱颖而出,今天我们一起来梳理 ...
- Android技术栈(五)HashMap(包括红黑树)与ArrayMap源码解析
1 总览 本文会对 Android 中常用HashMap(有红黑树)和ArrayMap进行源码解析,其中 HashMap 源码来自 Android Framework API 28 (JDK=1.8) ...
- hashmap为什么用红黑树_关于HashMap的实现,一篇文章带你彻底搞懂,再也不用担心被欺负
推荐学习 刷透近200道数据结构与算法,成功加冕"题王",挤进梦中的字节 面试官杠上Spring是种什么体验?莫慌,送你一套面试/大纲/源码 前言 在介绍HashMap之前先了解一 ...
最新文章
- (转)基于MVC4+EasyUI的Web开发框架经验总结(14)--自动生成图标样式文件和图标的选择操作...
- @select注解模糊查询_mybatis @SelectProvider 注解, 打赌你没有用过
- ICLR 2022入选论文线上分享预告:一作解读,不容错过
- 十进制小数转换为二进制
- python用字典存储学生信息网_用Python存储字典的四种方法
- C语言学习之输出10个整数中的最大值及其下标、最小值及其下标
- java面试题十三 string创建了几个对象
- 贝叶斯分析好坏_贝叶斯统计 | 第五章第一部分 决策基本概念
- ad域 禁用账号_IST-AD域信息同步平台来袭
- Python 判断字典是否有key,判断字典key的个数
- linux安装到内存中,Linux安装识别大内存的补丁程序
- tableau free public免费版
- Spring常用注解(全常用)
- linux复制特定类型文件,Linux复制指定目录及子目录下特定类型的文件
- Move: 一门面向资产的编程语言
- java-php-python-ssm学生学籍信息管理系统计算机毕业设计
- 大疆2019届秋招笔试--测试工程师
- 微信小程序-增加水印(自定义内容)
- 硬件工程师成长之路(11)——职业规划
- usb连接不上 艾德克斯电源_艾德克斯 ITECH电源RS232通讯设置简易教程