RB-INSERT-FIXUP(T, z)
01 while color[p[z]] = RED // 若“当前节点(z)的父节点是红色”,则进行以下处理。
02 do if p[z] = left[p[p[z]]] // 若“z的父节点”是“z的祖父节点的左孩子”,则进行以下处理。
03 then y ← right[p[p[z]]] // 将y设置为“z的叔叔节点(z的祖父节点的右孩子)”
04 if color[y] = RED // Case 1条件:叔叔是红色
05 then color[p[z]] ← BLACK ▹ Case 1 // (01) 将“父节点”设为黑色。
06 color[y] ← BLACK ▹ Case 1 // (02) 将“叔叔节点”设为黑色。
07 color[p[p[z]]] ← RED ▹ Case 1 // (03) 将“祖父节点”设为“红色”。
08 z ← p[p[z]] ▹ Case 1 // (04) 将“祖父节点”设为“当前节点”(红色节点)
09 else if z = right[p[z]] // Case 2条件:叔叔是黑色,且当前节点是右孩子
10 then z ← p[z] ▹ Case 2 // (01) 将“父节点”作为“新的当前节点”。
11 LEFT-ROTATE(T, z) ▹ Case 2 // (02) 以“新的当前节点”为支点进行左旋。
12 color[p[z]] ← BLACK ▹ Case 3 // Case 3条件:叔叔是黑色,且当前节点是左孩子。(01) 将“父节点”设为“黑色”。
13 color[p[p[z]]] ← RED ▹ Case 3 // (02) 将“祖父节点”设为“红色”。
14 RIGHT-ROTATE(T, p[p[z]]) ▹ Case 3 // (03) 以“祖父节点”为支点进行右旋。
15 else (same as then clause with "right" and "left" exchanged) // 若“z的父节点”是“z的祖父节点的右孩子”,将上面的操作中“right”和“left”交换位置,然后依次执行。
16 color[root[T]] ← BLACK
根据被插入节点的父节点的情况,可以将"当节点z被着色为红色节点,并插入二叉树"划分为三种情况来处理。 ① 情况说明:被插入的节点是根节点。 处理方法:直接把此节点涂为黑色。 ② 情况说明:被插入的节点的父节点是黑色。 处理方法:什么也不需要做。节点被插入后,仍然是红黑树。 ③ 情况说明:被插入的节点的父节点是红色。 处理方法:那么,该情况与红黑树的“特性(5)”相冲突。这种情况下,被插入节点是一定存在非空祖父节点的;进一步的讲,被插入节点也一定存在叔叔节点(即使叔叔节点为空,我们也视之为存在,空节点本身就是黑色节点)。理解这点之后,我们依据"叔叔节点的情况",将这种情况进一步划分为3种情况(Case)。
第一步:将红黑树当作一颗二叉查找树,将节点删除。 这和"删除常规二叉查找树中删除节点的方法是一样的"。分3种情况: ① 被删除节点没有儿子,即为叶节点。那么,直接将该节点删除就OK了。 ② 被删除节点只有一个儿子。那么,直接删除该节点,并用该节点的唯一子节点顶替它的位置。 ③ 被删除节点有两个儿子。那么,先找出它的后继节点;然后把“它的后继节点的内容”复制给“该节点的内容”;之后,删除“它的后继节点”。在这里,后继节点相当于替身,在将后继节点的内容复制给"被删除节点"之后,再将后继节点删除。这样就巧妙的将问题转换为"删除后继节点"的情况了,下面就考虑后继节点。 在"被删除节点"有两个非空子节点的情况下,它的后继节点不可能是双子非空。既然"的后继节点"不可能双子都非空,就意味着"该节点的后继节点"要么没有儿子,要么只有一个儿子。若没有儿子,则按"情况① "进行处理;若只有一个儿子,则按"情况② "进行处理。
RB-DELETE(T, z)
01 if left[z] = nil[T] or right[z] = nil[T]
02 then y ← z // 若“z的左孩子” 或 “z的右孩子”为空,则将“z”赋值给 “y”;
03 else y ← TREE-SUCCESSOR(z) // 否则,将“z的后继节点”赋值给 “y”。
04 if left[y] ≠ nil[T]
05 then x ← left[y] // 若“y的左孩子” 不为空,则将“y的左孩子” 赋值给 “x”;
06 else x ← right[y] // 否则,“y的右孩子” 赋值给 “x”。
07 p[x] ← p[y] // 将“y的父节点” 设置为 “x的父节点”
08 if p[y] = nil[T]
09 then root[T] ← x // 情况1:若“y的父节点” 为空,则设置“x” 为 “根节点”。
10 else if y = left[p[y]]
11 then left[p[y]] ← x // 情况2:若“y是它父节点的左孩子”,则设置“x” 为 “y的父节点的左孩子”
12 else right[p[y]] ← x // 情况3:若“y是它父节点的右孩子”,则设置“x” 为 “y的父节点的右孩子”
13 if y ≠ z
14 then key[z] ← key[y] // 若“y的值” 赋值给 “z”。注意:这里只拷贝z的值给y,而没有拷贝z的颜色!!!
15 copy y's satellite data into z
16 if color[y] = BLACK
17 then RB-DELETE-FIXUP(T, x) // 若“y为黑节点”,则调用
18 return y
RB-DELETE-FIXUP(T, x)
01 while x ≠ root[T] and color[x] = BLACK
02 do if x = left[p[x]]
03 then w ← right[p[x]] // 若 “x”是“它父节点的左孩子”,则设置 “w”为“x的叔叔”(即x为它父节点的右孩子)
04 if color[w] = RED // Case 1: x是“黑+黑”节点,x的兄弟节点是红色。(此时x的父节点和x的兄弟节点的子节点都是黑节点)。
05 then color[w] ← BLACK ▹ Case 1 // (01) 将x的兄弟节点设为“黑色”。
06 color[p[x]] ← RED ▹ Case 1 // (02) 将x的父节点设为“红色”。
07 LEFT-ROTATE(T, p[x]) ▹ Case 1 // (03) 对x的父节点进行左旋。
08 w ← right[p[x]] ▹ Case 1 // (04) 左旋后,重新设置x的兄弟节点。
09 if color[left[w]] = BLACK and color[right[w]] = BLACK // Case 2: x是“黑+黑”节点,x的兄弟节点是黑色,x的兄弟节点的两个孩子都是黑色。
10 then color[w] ← RED ▹ Case 2 // (01) 将x的兄弟节点设为“红色”。
11 x ← p[x] ▹ Case 2 // (02) 设置“x的父节点”为“新的x节点”。
12 else if color[right[w]] = BLACK // Case 3: x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的左孩子是红色,右孩子是黑色的。
13 then color[left[w]] ← BLACK ▹ Case 3 // (01) 将x兄弟节点的左孩子设为“黑色”。
14 color[w] ← RED ▹ Case 3 // (02) 将x兄弟节点设为“红色”。
15 RIGHT-ROTATE(T, w) ▹ Case 3 // (03) 对x的兄弟节点进行右旋。
16 w ← right[p[x]] ▹ Case 3 // (04) 右旋后,重新设置x的兄弟节点。
17 color[w] ← color[p[x]] ▹ Case 4 // Case 4: x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的。(01) 将x父节点颜色 赋值给 x的兄弟节点。
18 color[p[x]] ← BLACK ▹ Case 4 // (02) 将x父节点设为“黑色”。
19 color[right[w]] ← BLACK ▹ Case 4 // (03) 将x兄弟节点的右子节设为“黑色”。
20 LEFT-ROTATE(T, p[x]) ▹ Case 4 // (04) 对x的父节点进行左旋。
21 x ← root[T] ▹ Case 4 // (05) 设置“x”为“根节点”。
22 else (same as then clause with "right" and "left" exchanged) // 若 “x”是“它父节点的右孩子”,将上面的操作中“right”和“left”交换位置,然后依次执行。
23 color[x] ← BLACK
现在,我们面临的问题,由解决"违反了特性(2)、(4)、(5)三个特性"转换成了"解决违反特性(1)、(2)、(4)三个特性"。RB-DELETE-FIXUP需要做的就是通过算法恢复红黑树的特性(1)、(2)、(4)。RB-DELETE-FIXUP的思想是:将x所包含的额外的黑色不断沿树上移(向根方向移动),直到出现下面的姿态: a) x指向一个"红+黑"节点。此时,将x设为一个"黑"节点即可。 b) x指向根。此时,将x设为一个"黑"节点即可。 c) 非前面两种姿态。
将上面的姿态,可以概括为3种情况。 ① 情况说明:x是“红+黑”节点。 处理方法:直接把x设为黑色,结束。此时红黑树性质全部恢复。 ② 情况说明:x是“黑+黑”节点,且x是根。 处理方法:什么都不做,结束。此时红黑树性质全部恢复。 ③ 情况说明:x是“黑+黑”节点,且x不是根。 处理方法:这种情况又可以划分为4种子情况。这4种子情况如下表所示:
现象说明
处理策略
Case 1
x是"黑+黑"节点,x的兄弟节点是红色。(此时x的父节点和x的兄弟节点的子节点都是黑节点)。