数据结构之2-3树和红黑树剖析
概述
红黑树(英语:Red–black tree)是一种自平衡二叉查找树,它在1972年由鲁道夫·贝尔发明,被称为"对称二叉B树",它现代的名字源于Leo J. Guibas和Robert Sedgewick于1978年写的一篇论文。
红黑树和AVL树一样都对插入时间、删除时间和查找时间提供了最好可能的最坏情况担保。
《算法导论》中的红黑树:
- 1.每个节点或者是红色的,或者是黑色的
- 2.根节点是黑色的
- 3.每一个叶子节点(最后的空节点)是黑色的
- 4.如果一个节点是红色的,那么他的孩子节点都是黑色的
- 5.从任意一个节点到叶子节点,经过的黑色节点是一样的。
这些约束确保了红黑树的关键特性:
- 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。
- 结果是这个树大致上是平衡的。
- 因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
- 性质4导致了路径不能有两个毗连的红色节点。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据性质5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。
要学习红黑树,我们需要先学习2-3树,任一棵2-3树都可以按照特定规则转换为一棵红黑树。
2-3树
2-3树:
- 满足二分搜索树的基本性质
- 节点可以存放一个元素或者两个元素
- 2-3树是一棵绝对平衡的树;绝对平衡的树:对任意一个子树,它的左、中、右子树的高度是相等的。
2-3树示例:
2-3树如何维持绝对的平衡:
- 在2-3树中添加新节点永远不会添加到一个空的位置,只会和最后找到的叶子节点做融合;
- 在2-3树中只会存在两种节点:2节点和3节点;
- 如果是一个2节点添加一个新节点,直接融合变成一个3节点即可;
- 如果一个3节点添加一个新节点变成一个临时的4节点,要对其进行拆解;
- 拆解:
- 对于2-3树来说,如果一个叶子节点本身是一个3节点,添加一个新节点变成一个临时的4节点,
- 拆解之后的根节点要和其父节点进行融合,融合之后的父节点也要为2节点或3节点否则也要进行拆解,
- 依此递归向上,直到父节点为2节点与其融合或为整棵树的根节点结束;
插入情况一:插入3节点,父亲节点为2节点
- 新添加的节点与3节点进行融合,进行拆分,拆分后根节点的父节点为2节点,与父节点融合即可;
插入情况二:插入3节点,父新节点为3节点
- 如果一个叶子节点本身是一个3节点,添加一个新节点变成一个临时的4节点,
- 拆解之后的根节点要和其父节点进行融合,融合之后的父节点也要为2节点或3节点否则也要进行拆解,
- 依此递归向上,直到父节点为2节点与其融合或为整棵树的根节点结束;
2-3树插入示例:
2-3树插入示例:
2-3树与红黑树的等价性
2-3树与红黑树的节点对应关系:
- 2-3树中的 2节点 对应红黑树中的 黑节点 ;
- 为便于理解红黑树,采用左倾红黑树,定义:2-3树中的3节点,都对应红黑树中的黑节点和左孩子节点为红节点的两个节点;
2-3树与红黑树转换示例:
- 依据上述节点转换规则,任何一棵2-3树都可以转换为相应的红黑树;
2-3树 转换的红黑树 与《算法导论》中的红黑树 验证 :
- 1.每个节点或者是红色的,或者是黑色的;
- 验证:2-3树的2节点 与 3节点转换成红黑树的节点 要么是黑色节点,要么是一个黑节点和一个左倾的红节点;
- 满足;
- 2.根节点是黑色的
- 验证:2-3树的2节点 与 3节点转换成红黑树的节点,新的节点的根节点都为黑节点;
- 满足;
- 3.每一个叶子节点(最后的空节点)是黑色的
- 相当于定义空节点为黑节点,相当于一个空树也是一个红黑树;与第2条性质相关联;
- 满足;
- 4.如果一个节点是红色的,那么他的孩子节点都是黑色的
- 在2-3树转换的红黑树中,只有一种情况会出现红节点,即 3节点 转换成 一个黑节点和一个左倾的红节点;
- 在2-3树3节点只会连接2节点或3节点,转换后的红节点的孩子节点只会是黑节点;
- 满足;
- 5.从任意一个节点到叶子节点,经过的黑色节点是一样的。
- 在2-3树中对应的是:从任意一个节点出发到叶子节点,所经过的节点数是一样的;
- 2-3树是一棵绝对平衡的树,所有的叶子节点都是在同一层的,它的深度是相同的,这样从任意一个节点出发,向下到叶子节点,其深度都是相同的,即所经过的节点数量是一样的;
- 2-3树中只有2节点和3节点,转换成红黑树后,每一个2节点或3节点都只会对应一个黑节点;所以,在红黑树中,每经过一个黑节点,即相应的在2-3树中经过了一个节点,即得出在红黑树中从任意一个节点到叶子节点,经过的黑色节点是一样的;
- 红黑树是一棵保持黑平衡的二叉搜索树;其并不是平衡二叉树;
- 红黑树最大的高度为: 2logn , 时间复杂度为: O(logn)
- 满足;
红黑树
红黑树中添加新元素与2-3树中添加元素对应关系:
- 2-3树中添加一个新元素:
- 或者添加进一个2节点,形成一个3节点;
- 或者添加进一个3节点,暂时形成一个4节点,再对4节点进行拆分;
- 在红黑树中添加新节点,永远添加红色节点
- 在2-3树中添加新节点,永远不会添加到空的位置,只会和最后找到的叶子节点进行融合;
- 在2-3树转换成左倾红黑树中,其中红节点对应2-3树中的3节点转换成一个黑节点和红色的左孩子节点;
- 因此,我们在红黑树中添加新的元素时,我们让新的元素节点永远是红色节点;等价于在2-3树中添加新一元素节点永远是先融合进一个已有的节点中;
- 在红黑树中添加一个新元素红节点后,可能会破坏红黑树的性质,需要再进行相应的处理,维持红黑树的性质;
红黑树添加新元素
红黑树添加新元素分析:
- 在红黑树中新添加元素都是红节点;
- 因为2-3树都可转换成为一棵红黑树,采用与2-3树中添加元素类比的方式,完成向红黑树中添加元素分析;
红黑树添加新元素类比向2-3树中添加元素情况分析:
- 添加元素情况一:向空树中添加元素
- 添加元素情况1:向空树中添加元素,在红黑树中保持根节点为黑节点;
- 添加元素情况二:类似向2-3树中的2节点添加元素,变成3节点
- 添加元素情况2:类似2-3树中向2节点添加比其小的元素,无需任何处理
- 添加元素情况3:类似2-3树中向2节点添加比其大的元素,需要进行:左旋转
- 添加元素情况三:类似向2-3树中的3节点添加元素,变成临时4节点,再进行拆分
- 添加元素情况4:类似向2-3树中的3节点添加比该节点值都大的元素,在红黑树中需要进行 颜色翻转
- 添加元素情况5:类似向2-3树中的3节点添加比该节点值都小的元素**,在红黑树中需要进行: 右旋转 和 颜色翻转:
- 添加元素情况6:类似向2-3树中的3节点添加元素值大小处于中间位置的元素**,在红黑树中需要进行:左旋转、右旋转 和 颜色翻转
添加元素情况1:向空树中添加元素:
- 保持根节点为黑节点;
添加元素情况2:类似2-3树中向2节点添加比其小的元素,无需任何处理:
添加元素情况3:类似2-3树中向2节点添加比其大的元素,需要进行:左旋转
左旋转处理:
添加元素情况4:类似向2-3树中的3节点添加比该节点值都大的元素,在红黑树中需要进行 颜色翻转:
- 向2-3树中的3节点添加比该节点值都大的元素,2-3树变成临时4节点,需要进行拆分,拆分后新的根节点需要其上一级父节点进行融合;
- 在红黑树中使用红节点代表,保持左倾红黑树特性,对节点进行颜色翻转。
添加元素情况5:类似向2-3树中的3节点添加比该节点值都小的元素,在红黑树中需要进行: 右旋转 和 颜色翻转:
- 向2-3树中的3节点添加比该节点值都大的元素,2-3树变成临时4节点,需要进行拆分,拆分后新的根节点需要其上一级父节点进行融合;
- 对应红黑树中添加元素后,需要进行右旋转再进行颜色翻转处理;
- 右旋转:
- 与平衡二叉树中进行右旋转一致,右旋转后需要维护红黑树的节点的颜色;
- 原先的根节点的颜色要赋值给新的根节点;
- 右旋转后在2-3树中仍代表临时4节点,需要将新的左右孩子颜色变为红色,代表其是与其父节点融合在一起的;
- 颜色翻转
- 经过右旋转之后,新的子树形状便与上一种情况一致了,按上述颜色翻转处理即可完成元素插入;
添加元素情况6:类似向2-3树中的3节点添加元素值大小处于中间位置的元素,在红黑树中需要进行:左旋转、右旋转 和 颜色翻转:
红黑树中添加元素处理操作汇总:
- 通过下述添加元素的链条示意图,将类似向2-3树中的3节点添加元素的所有情况全部覆盖;
- 该逻辑链条同样适用于类似向2-3树中的2节点添加元素的所有情况;
- 基于下述处理链条,可以完成向红黑树中添加元素后,维护红黑树特性所需要处理的所有情况。
添加元素后红黑树性质维护处理步骤:
- 检验当前节点是否需要左旋转,条件:当前节点右孩子为红节点且其左孩子不能为红节点;
- 检验当前节点是否需要右旋转,条件:当前节点左孩子为红节点且当前节点左孩子的左孩子为红节点;
- 检验当前节点是否需要颜色翻转,条件:当前节点左孩子为红节点且当前节点右孩子为红节点;
- 依上述规则处理,递归向上,直到根节点返回,递归结束;
- 递归结束后,保持红黑树的根节点为黑节点;
- 注意:如果是一个空节点,其为黑节点;
更多和红黑树相关的话题:
- 红黑树中删除一个节点,相应的逻辑过程比添加元素还要复杂;
- 红黑树的统计性能更优,即增、删、改、查操作综合起来评估比AVL性能更优;
- 本次讲述的红黑树,采用左倾红黑树,在红黑树中,对应2-3树中的3节点为一个黑节点和一个其左孩子红节点;但这并不是红黑树惟一的实现方式,同理也可以采用右倾红黑树实现;
- 另一种统计性能优秀的树结构-Splay Tree(伸展树),局部性原理:刚被访问的内容下次高概率被再次访问;
实现
基于二叉搜索树实现红黑树中添加元素
参考代码: com.chen.data.struct.redblack.RBTree
相关链接
gitee地址:https://gitee.com/chentian114/chen_datastruct_study
github地址:https://github.com/chentian114/chen_datastruct_study
CSDN地址:https://blog.csdn.net/chentian114/category_9997109.html
公众号
参考
刘宇波《玩转数据结构》课程
https://www.wiki-wiki.top/wiki/红黑树