| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 图解红黑树 -> 正文阅读 |
|
[数据结构与算法]图解红黑树 |
写在前面阅读本文你需具备知识点: 红黑树也是一棵二叉查找树,既然有了AVL树为什么还需要红黑树呢? 之前在了平衡二叉树AVL实现中讲到了为什么使用平衡二叉树AVL(解决二叉查找树退化为类似链表的问题),最大的作用就是用于查找,其时间复杂度为O(logn),但AVL树插入或删除节点后,若使得高度之差大于1,此时,AVL树的平衡状态就被破坏,需要旋转才能达到平衡。因此如果在插入和删除频繁的场景中就需要频繁的调整使之达到平衡,性能也随之下降。 因此,红黑树的提出是为了解决平衡树在插入和删除等操作频繁的情况。 在了解红黑之前先看看2-3-4树。 2-3-4树在二叉树中,每个节点有一个数据项(可以理解为节点的值,key),最多有2个子节点。如果允许每个节点可以有更多的数据项和子节点,就是多叉树,2-3-4树就属于多叉树,并且还是平衡树(B树)。 2-3-4树是一种阶(阶,可以理解为节点的分支)为4的B树,所以也可称它为4叉树,主要具备以下性质:
如下面这棵2-3-4树: 在上图中: 有2个链接的为2节点 有3个链接的为3节点 有4个链接的为4节点 插入操作2-3-4树的插入总是在叶子节点且一般不允许插入重复的key。 若插入时的叶子节点不是满节点(即4节点),如插入数据45,如下: 节点分裂如果插入节点是4节点,这时候节点就需要分裂才能保证树的平衡(这里假设分裂的节点不是根节点),一个4节点可以分裂成一个根节点和两个子节点(这三个节点各含一个key)然后在子节点中插入。若分裂的节点数据分别用ABC来表示: 若分裂节点的父节点也是满节点,则按照分裂操作继续分裂即可。 2-3-4树的删除如果感兴趣的可自己去百度,网上很多 红黑树红黑树也是一棵二叉查找树,也是一棵自平衡树,具备以下性质:
如下面这个常见的红黑树: 通过以上性质,可以推出:从根节点到叶子节点的最长路径不会超过最短路径的2倍 为什么? 根据上面的性质5我们知道下图的红黑树每条路径上都是3个黑结点。因此最短路径长度为2(没有红结点的路径)。再根据性质4(没有连续的红色节点)和性质2,3(叶 子和根必须是黑结点)。那么我们可以得出: 最短路径:一条具有3个黑结点的路径上最多只能有2个红结点(红黑间隔存在),最短路径为2。 最长路径:黑深度为2(根结点也是黑色)的红黑树最长路径为4。 从这一点我们可以看出红黑树是大致平衡的。 (比平衡二叉树要差一些,AVL的平衡因子最多为1) 注:若以下有说道性质1-5,分别表示上述性质,如性质2表示“根节点是黑色”。 2-3-4树和红黑树的等价关系红黑树起源于2-3-4树,一颗红黑树对应一颗确定的2-3-4树,一颗2-3-4树对应多个红黑树。 上面的2-3-4树和红黑树看上去完全不同,但实际上是等价的,通过一些规则可以让2-3-4树变为红黑树,如: 上图中3节点存在2种情况:
因此,这就决定了一颗红黑树对应一颗确定的2-3-4树,一颗2-3-4树对应多个红黑树。 然后我们把最开始的那棵2-3-4树按照上面的规则转化为红黑树,如下: 节点之间的转化对应如下: 由规则生成的红黑树: 那么到底2-3-4树和红黑树是怎么对应的?就是上面简单的替换吗?那我插入或删除的时候怎么调整,通过什么规则去调整,我们继续往下分析。 左倾红黑树在上面等价替换中,3节点可以转化为2中不同类型的红黑树,即左倾红黑树和右倾红黑树,下面的内容主要通过左倾红黑树来讲解。 那什么是左倾红黑树呢? 一个节点要么有一个子节点,要么有两个子节点,如果有一个红色子节点,那么这个子节点只能在左边,如果有2个红色子节点,那就是两边都是红色。右倾红黑树同理: 了解了左倾红黑树,我们再看看红黑树的调整和它以及2-3-4树有什么关系,继续往下看。 红黑树的调整插入操作根据上面的性质,如果我们在插入一个元素的时候违反了,此时我们需要调整才能使其遵守上述性质。而调整方式只有以下2种可能:
旋转和变色左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变 右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变 这里的插入操作主要通过从插入节点的过程和左倾红黑树以及右倾红黑树的规则来分析插入过程中存在的情况。 基本定义:
下面的1-5序号表示从根节点(包括根节点)开始插入的第几个节点。
至此,红黑树插入节点的情形都分析完成,如果理解了2-3-4树到红黑树的转变,就不用去死记插入节点时会碰到那些情况。 小结通过上面插入操作的分析,插入的情形可以总结出以下几点:
删除操作红黑树的删除如果还原为2-3-4树分析个人感觉复杂很多,所以这里还是按照二叉排序树的删除方式来分析。红黑树的删除和二叉排序树类似,也分为3种情况,即删除节点无子节点,有1个子节点和有2个子节点三中情况,也就是说红黑树的删除要先考虑是否有子节点再考虑删除节点的颜色。所以在红黑树的删除中,存在6种情形(3*2)。 无子节点
由红黑树的性质4和5可知,若删除节点为红色,则其父节点必为黑色,所以这种情况不会破坏红黑树的性质,直接删除即可。如下图删除节点
这种情况是比较复杂的,建议先看完其他几种在回头来看。 情形二的删除情形又分为以下几种: ① 删除节点的兄弟节点为黑色,且兄儿子与兄同边(左或右)红色 上图中,删除节点D,则经过D路径的黑色节点减少1个,以P为支点旋转,将B节点旋转(左旋)到P的位置, 并把与B同边的BS节点变为黑色,P节点变为黑色,并将替代节点null删除,达到局部平衡。 同理,若节点D在右边,节点B,BS在左边,那就是右旋+变色即可达到平衡。 ② 删除节点的兄弟节点为黑色,且兄儿子与兄不同边(左或右)红色 将BS和B旋转(右旋),变色,变成①。 同理,节点D在右边,节点B,BS在左边,左旋+变色,变成①。 ③ 删除节点的兄弟节点为黑色,且兄弟节点的子节点为黑色
④ 删除节点的兄弟节点为红色 若删除节点的兄弟节点为红色,则其父节点必为黑色,且B的子节点也为黑色节点 这里我们把节点B进行左旋和变色操作: 从上图可以看出旋转之后删除节点D的兄弟节点变为了黑色节点BSL,这就是前面分析的情形①或②。 这里就可以解释为什么红黑树的删除最多需要三次旋转:
所以整个过程只需要旋转三次即可达到平衡,这也是为什么删除要优于AVL的原因。 有一个子节点
这种情况如下: 由红黑树的性质4和5可知,在构建一棵红黑树的时候,任意节点的路径都具有相同的黑色节点,且红色节点和红色 节点不连续,所以若删除节点为红色其子节点必为黑色,这样就破坏了性质5,所以这种情况在构建红黑树的时候 就不会存在,所以删除的情况也不会存在。
若删除节点为黑色,则其子节点必为红色(为黑色则不满足性质5),所以删除节点后只需要用子节点替换然后变 色即可(因为黑色节点被删除,由于性质5,所以需要把子节点在变为黑色)。如删除节点 有两个子节点节点的删除可以通过前驱节点(删除节点左子树中的最大值)或后继节点(删除节点右子树中的最小值)替换掉要删除的节点,若通过后继节点删除,存在2种情况: 所以,用后继节点代替要删除节点,转化为删除后继节点,通过判断后继节点的删除来调整。 若后继节点是①的情况:
若后继节点是②的情况:
有2个节点的删除通过后继节点的方式,如果是前驱节点的方式,可能又是不一样的,但分析过程却是差不多的。 小结这里的红黑树的删除是根据删除节点是否存在子节点来分析的,但总结一下上面的六种情形,情形五和情形六同时被转化为上面的一,二,四,所以我们只需要掌握这三种即可。 判断属于那种情形的时候,通过下面的顺序:
红黑树和AVL的区别
所以,在实际应用中,若搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RB。 总结在学习红黑树的时候查阅了很多资料,同时也让我很头疼,比如它和AVL的增删效率到底怎么去计算,明明在新增的时候旋转的次数都是两次,有的博文却说AVL要高于2次,10篇文章就有10种说法,但是我还是坚持自己在实际操作中所记录下的。 本来准备把代码贴上来,但是我觉得没必要,因为在面试中也不会有面试官叫你手写红黑树,如果有,请把键盘给他,他行他上。而且对于我们实际开发也没有太大用处,也可能一辈子都不会去手写一个红黑树,比如你不会去自己实现HashMap,所以没有必要动不动就什么死磕红黑树的,我们只需要知道他的基本逻辑就行了,如新增的时候怎么旋转保持平衡,删除的时候怎么旋转保持平衡的逻辑就够了。而在你有一定代码能力之后,很可能你就自己能写一个简单的demo了,写代码的前提就是要清晰的知道逻辑。 这里还是把代码提供出来,需要的可自行去下载: 之前有人问上面的动图是怎么做的,数据结构可视化: 参考 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 | -2024/12/27 9:42:28- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |