| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 红黑树的详解 -> 正文阅读 |
|
[数据结构与算法]红黑树的详解 |
文章目录1. 红黑树的提出友情提示:本文需要在了解平衡二叉树、AVL树和B-树的背景下阅读,如果对这三个数据结构还不了解的小伙伴可以读一下我的另外三篇文章:【数组模拟二叉搜索树(二叉排序树)】、【数组模拟AVL树(平衡二叉树)】、【B-树的详解】。 既然平衡树家族中已经有了AVL树这种成员,并且其时间复杂度已经达到了 O ( l o g h ) O(logh) O(logh) 的要求,那么为啥要提出红黑树呢? 我们来回顾一下AVL树的操作:
因此,在涉及到大量的动态操作时,我们希望其引发的结构变化量不超过 O ( 1 ) O(1) O(1),对树型拓扑结构的影响都能控制在常数的范围之内。而红黑树,就是这样的一种树型结构。 2. 红黑树的定义红黑树是由红、黑两类结点组成的二叉搜索树,和B-树类似,红黑树将所有的内部结点都增设了外部结点
如果将红黑树比作人,可以将树根看成人的帽子,外部结点看做人的靴子,下图是一棵红黑树。 那么,有没有什么更为直观的解释呢?这里,为了更好的理解红黑树,我们要先介绍一种树型结构的另一种等价拓扑变换—提升变换。 提升变换:将每一个红色结点从视觉上提升到其黑色的父亲结点一侧,如下图: 下图是变换之前的某棵红黑树: 提升各个红色结点,使之与其父亲黑色结点等高,从这个角度来看,每一棵红黑树就是4阶的B-树,也就是(2, 4)-树,如果你对B-树不熟悉,可以看我的另一篇博客:【B-树的详解】。 因此我们只需要将红黑树中的黑色结点与其上提的红色孩子(关键字合并)视作4阶B-树中的一个结点 ,根据黑色根结点左右孩子的颜色分为四种组合,每种组合分别对应于4阶B-树的一类内部结点: 3. 红黑树的查找红黑树的查找操作和传统的二叉搜索树一致,这里不再赘述。 4. 红黑树的插入与了解红黑树的定义一样,我们会发现红黑树和与其对应的“影子B-树”之间的关系非常好理解,而且反过来也是如此,这样理解红黑树的原理表面看来有点迂回,但我们很快就会感受到,这种间接的理解方式学习红黑树反而是效率最高的。 4.1 插入操作的算法框架
下面,重点介绍插入中双红缺陷的处理办法: 先分析一波: 先考察 x x x 的祖父结点 g = p → p a r e n t g = p→parent g=p→parent ,注意这里的祖父结点 g g g 一定是存在的,否则 p p p 不会为红色,并且祖父结点 g g g 一定为黑色。 然后,我们还要考察 g g g 的另外一个孩子 u u u,相对于 x x x 而言。结点 u u u 是 x x x 的叔父,当然,结点 u u u 的颜色也是不定的,我们要根据结点 u u u 的颜色分别处理。 4.2 调整:双红缺陷4.2.1 双红缺陷1:叔父结点 u 是黑色此时,
x
x
x,
p
p
p,
g
g
g 的四个子树的根(可能是外部结点)必定全部为黑,且黑高度相同,依据
x
x
x 在
p
p
p 的左右关系,可以分为下面两种情况。 为了更好的研究这两种红色缺陷,我们将红色结点提升: 对于处理 ( a ′ ) (a') (a′) 中的情况,只需要交换 p p p 和 g g g 的颜色即可。同理, ( b ′ ) (b') (b′) 中的情况,只需要交换 x x x 和 g g g 的颜色即可。 我们刚刚这种角度实际上是将其用B-树的角度来处理双红缺陷,如果用这种方式处理的话,还要分情况讨论是 p p p 还是 x x x 去与 g g g 交换颜色,再结合尚未列出的两个镜像的情况,共4种不同的交换颜色的处理方式,分类讨论很麻烦。 实际中真正处理叔父结点是黑色情况下的双红缺陷的办法: 在实际操作中,只要是出现了双红缺陷,并且 x x x 的叔父 u u u 是黑色,统一采用下面步骤处理双红缺陷: (1)参考AVL树算法,做局部的重构,将结点 x x x、 p p p、 g g g 这三个结点以及它们下属的四棵子树找出来,这里可以结合图 ( a ) (a) (a),然后从 g g g 对这一局部开始中序遍历,获得一个中序遍历的有序序列: [ T 0 < a < T 1 < b < T 2 < c < T 3 ] [T_0<a<T_1<b<T_2<c<T_3] [T0?<a<T1?<b<T2?<c<T3?],从新构建排布方式: (2)直接将中间结点
b
b
b 染黑,
a
a
a 和
c
c
c 染红,如下图。 首先,调整之前之所以非法,是因为在(2,4)-树中某个三叉结点中插入了红色的关键字形成了四叉结点,使得原来黑色的关键字不再居中,形成了 而调整之后的效果相当于B-树的拓扑结构不变,但是在新的四叉结点中,三个关键字的颜色改为 4.2.2 双红缺陷2:叔父结点 u 是红色
因此,与其说我们是在红黑树中修复双红缺陷,不如说我们在4阶B-树中修复上溢缺陷,这二者完全是一回事,见下图。 (1)先将红色结点上升,得到如 ( b ′ ) (b') (b′) 所示的效果 (2)计算 s = ? 4 2 ? = 2 s = \lceil \frac{4}{2} \rceil = 2 s=?24??=2,我们将 [ k 0 , k 1 , k 2 , k 3 ] [k_0,k_1,k_2,k_3] [k0?,k1?,k2?,k3?] 中的 k s = k 2 k_s=k_2 ks?=k2? 上提到该上溢结点的父结点中,将 [ k 2 ] [k_2] [k2?] 由黑色染成红色(相当于对上溢结点的父结点插入一个新的结点,所以要染成红色) ,同时将其原来的左右孩子染成黑色(因为红色结点的孩子都是黑色)即可。 (3)我们说将 k 2 k_2 k2? 染红并且上提看做作为新结点插入到上溢结点的父结点,因此上溢的结点的父结点有可能因为这个插入也发生双红缺陷。那么我们递归地再对该结点判断其叔父颜色,递归地执行对应颜色的双红结点的处理。最坏的情况下也只是会递归的处理到根结点,因此整个双红缺陷蔓延的过程迟早会终止。 需要强调的一点是:尽管这一个调整过程,从B-树的角度来看,的确发生了拓扑结构的变化 。但是从红黑树的角度来看,除了相关结点的颜色发生了变化,红黑树的拓扑连接关系并没有发生变化。因此,红黑树的重染色操作的次数可能会高达 O ( l o g h ) O(logh) O(logh),但是拓扑结构的变化依然控制在 O ( 1 ) O(1) O(1) 的范围内。 5. 红黑树的删除相对于插入,红黑树的删除情况更多,也更为复杂一些。因此,我们更需要通过提升变换,将红黑树映射为B-树,并站在B-树的角度,翻过来理解红黑树的过程及原理。
【解释】我们可以针对删除后红黑树的性质逐条分析: (2)删除后在此局部有可能会出现两个红色结点相连的双红缺陷情况(假设之前 x x x 为黑, p 、 r p、r p、r 为红),当然这种情况可以通过之前在插入里学的解决办法处理。 (3)删除后在被删除结点 x x x 所在的通路上黑结点的数目(黑深度)却有可能发生变化。 下面,我们重点讲解如何对黑深度进行调整。 5.1 调整:x 与 r 存在红结点对于(3)中有一种情况比较好处理,也就是被删结点
x
x
x 与其替代者
r
r
r 两者中有一个是红色的,如下图 5.2 调整:双黑缺陷然而,遗憾的是有可能被删除的结点
x
x
x 以及他的替代者
r
r
r 在删除前都是黑色结点,这种情况我们也称为双黑缺陷 因为 x x x 和 r r r 都是黑色的,那么对应的4阶B-树中 x x x 将独立的成为一个结点,在唯一的这个关键字被删除之后,该结点也就自然发生了下溢。因此我们后面的调整算法与其说是修复“双黑缺陷”,不如说是修复B-树的下溢。 因此,只需借助B-树的下溢修复算法,即可得到对应的红黑树双黑修复算法。 5.2.1 双黑缺陷-1我们知道,发生了下溢时,第一件事情就是下溢结点左顾右盼,看看兄弟结点能否借一个结点过来。 因此,对应双黑缺陷-1的情况就是: x x x 相邻的左右兄弟结点 s s s 为黑,且至少拥有一个红孩子 t t t(这里很好理解,有了红孩子就可以上提和 s s s 合并,那么 x x x 的左兄弟就相当于能借一个盈余结点出来,如果遗忘的话请回顾B-树的操作) 经过旋转之后,红黑树调整的结果如右图,现在将右图中的
t
,
s
,
p
t,s,p
t,s,p 分别重命名为
a
,
b
,
c
a,b,c
a,b,c,
r
r
r 保持黑色,
a
,
c
a,c
a,c 染黑,
b
b
b 继承
p
p
p 的颜色,因为
s
s
s 继承了原来
p
p
p 的颜色,因此新的局部结构也不会对红黑树的其他部分造成影响。 5.2.2 双黑缺陷-2R双黑缺陷-2的情况就是:
x
x
x 相邻的左右兄弟结点
s
s
s 为黑,且两个孩子均为黑。但是这里还需要根据
s
s
s 和
x
x
x 的父结点
p
p
p 的颜色进行分类讨论,而双黑缺陷-2R就是双黑缺陷-2中,
p
p
p 为红色的情况。 那么这里有的小伙伴就会问了,因为原来B-树中 p p p 结点所在的结点因为下层合并借走了一个关键字,是否会因此造成原结点下溢呢?事实上是不会的,因为既然 p p p 是红色的,那么 p p p 的父结点一定是黑色的,故即使 p p p 被下面合并借走了以后也不会发生下溢。 这也是为什么我们要把 p p p 的颜色单独拎出来分类的原因。 5.2.3 双黑缺陷-2B而双黑缺陷-2R就是双黑缺陷-2中,
x
x
x 相邻的左右兄弟结点
s
s
s 为黑,且两个孩子均为黑,
p
p
p 为黑色的情况。 因此,双黑缺陷-2B的解决策略在拓扑结构的改变上依然是 O ( 1 ) O(1) O(1) 的,是非常高效的。 那么,之前我们讨论的双黑缺陷问题时,都是讨论在 s s s 为黑色结点的前提下的调整办法,那么当 s s s 为红色将如何处理呢? 5.2.4 双黑缺陷-3双黑缺陷-3是指:
x
,
r
x,r
x,r 为黑,
s
s
s 为红的情况。 实际上,对于这种情况我们并不需要做什么实质性的处理,而只需要将其转化为此前我们所介绍的某两种子情况,为此,我们必须还要站在对应B-树的角度分析问题,如下图。 首先,依然是红色结点上提,转换为B-树视角。因为是同一个结点之内,我们不妨直接上 s s s 和 p p p 互换颜色,而堆B-树无需做任何的结构调整。当然,当恢复到对应的红黑树之后,却需要做一次拓扑结构的调整,因为原来 s s s 的父亲指向 p p p,现在 p p p 的父亲指向 s s s,也就是相当于在红黑树中,围绕着结点 p p p,做一次AVL树中的右旋操作,同时互换 s s s 和 p p p 的颜色。 即使经过了上述处理,你可能有些失望,因为现在仍然没有解决黑高度变化问题。但是,我们可以发现,现在待删除结点 x x x 的兄弟 s ′ s' s′ 已经变为了黑色, x x x 的父结点已经变为了红色,于是我们就可以跳出双黑缺陷-3这种情况,而转入之前所讨论的情况。更具体一点,只会转入时间复杂度相对更小的双黑缺陷-1和双黑缺陷-2R这两种情况。 因此,我们可以断定,经过如此调整之后,红黑树的性质必然全局恢复。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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年11日历 | -2024/11/25 23:42:42- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |