本文内容主要参考并基于《算法导论》第二版
引言
本文对红黑树的几个关键的知识点进行介绍,包括:
1)红黑树的定义
2)如何增删结点
红黑树的定义
红黑树是一种满足以下性质的二叉查找树:
1)所有的结点要么是红色的,要么是黑色的
2)根结点是黑色的
3)叶子结点是黑色的
4)如果一个结点是红色的,则它的两个孩子都是黑色的
5)对于一个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点
需要注意的是,红黑树首先是一棵二叉查找树,即它要满足二叉查找树的所有性质。红黑树还有一个比较常用的概念——黑高度,具体定义可查阅相关资料。
如何增删结点
一、首先需要理解增删结点要用到两个常用操作:左旋和右旋
如上图,从左到右是对x左旋——LEFT-ROTATE(T,x),从右到左是对y右旋——RIGHT-ROTATE(T,y)。
理解左旋和右旋的一个关键点要知道操作的对象,严格来讲,单说左旋(右旋)是不对的,完整的说法应该是对某某左旋(右旋)。所以,对x左旋,是指把x和x的右孩子逆时针旋转;对x右旋,是指把x和x的左孩子顺时针旋转。
代码实现的时候需要注意,对每个结点,它的三个关键指针——父指针、左孩子、右孩子是否都已经正确处理。
另外需要注意的是,对红黑树的旋转不会改变结点的颜色。
二、插入结点
总的来说,插入结点分为三步(插入、着色、调整):
1)按照查找二叉树中插入结点的方法把新增的结点插入红黑树中
2)把新插入的结点着为红色
3)新插入的结点有可能破坏红黑树的5个性质,所以需要对此进行调整。
《算法导论》中把第三步叫做RB-INSERT-FIXUP(T, z) 。在这一步,算法会根据一些条件把结点z的状态分为三种情况,对每种情况做出不同的操作(改变颜色、左旋、右旋),直到满足红黑树的5个性质。其伪代码如下:
RB-INSERT-FIXUP(T, z)
1 while color[p[z]] = RED
2 do if p[z] = left[p[p[z]]]
3 then y ← right[p[p[z]]]
4 if color[y] = RED
5 then color[p[z]] ← BLACK ▹ Case 1
6 color[y] ← BLACK ▹ Case 1
7 color[p[p[z]]] ← RED ▹ Case 1
8 z ← p[p[z]] ▹ Case 1
9 else if z = right[p[z]]
10 then z ← p[z] ▹ Case 2
11 LEFT-ROTATE(T, z) ▹ Case 2
12 color[p[z]] ← BLACK ▹ Case 3
13 color[p[p[z]]] ← RED ▹ Case 3
14 RIGHT-ROTATE(T, p[p[z]]) ▹ Case 3
15 else (same as then clause
with "right" and "left" exchanged)
16 color[root[T]] ← BLACK
对这段代码的理解要注意以下几点:
1)z始终指向红节点
2)z的父结点是红节点
3)3种情况的划分取决于:
a. z的叔叔结点的颜色
b. z是左孩子还是右孩子
4)左旋或右旋操作不会改变结点的颜色
5)代码的第2至14行的前提是z的父结点是左结点
以下是对三种情况的说明:
case1:z的叔叔y是红色的
case2:z的叔叔y是黑色的,且z是右孩子
case3:z的叔叔y是黑色的,且z是左孩子
由于z的父结点是左结点,所以要把case2向case3变换,当z的父结点是右结点时,就应该是把case3向case2变换。
三、删除结点
本文详细介绍了红黑树的基本概念,包括其定义、增删结点的操作,特别是左旋和右旋。在增删结点过程中,通过着色和调整来维护红黑树的平衡。插入结点分为插入、着色、调整三个步骤,并提供了《算法导论》中的RB-INSERT-FIXUP伪代码,解释了三种不同情况的处理方式。
177万+

被折叠的 条评论
为什么被折叠?



