13.1红黑树的性质
def:红黑树是一棵二叉搜索树,其节点包括color、key、left、right和parent五个属性,通过对任何一条从根到叶子的简单路径上各个节点的颜色进行约束,红黑树确保没有一条路径会比其他路径长出2倍。
由引理可得对红黑树的search,minimu,maximum,successor和predecessor可以在O(lgn)时间内完成。
class COLOR:
RED = "red"
BLACK = "black"
class TREENODE():
def __init__(self, key, color=COLOR.BLACK, parent = None):
self.key = key
self.parent = parent
self.left = None
self.right = None
self.color = color
def setLeft(self, left):
self.left = left
left.parent = self
def setRight(self, right):
self.right = right
right.parent = self
def setColor(color):
self.color = color
class TREE():
def __init__(self):
self.nil = TREENODE(None)
self.root = self.nil
13.2旋转
def:交换节点与其子节点在树中的位置,并保持二叉搜索树性质不变的操作称为旋转。与right交换称为左旋(left rotate),与left交换称为右旋(right rotate)。左旋与又旋为互逆操作。
def LEFT_ROTATE(T, x):
y = x.right
x.right = y.left
if y.left != T.nil:
y.left.parent = x
y.parent = x.parent
if x.parent == T.nil:
T.root = y
elif x == x.parent.left:
x.parent.left = y
else:
x.parent.right = y
y.left = x
x.parent = y
def RIGHT_TOTATE(T, x):
y = x.left
x.left = y.right
if y.right != T.nil:
y.right.parent = x
y.parent = x.parent
if x.parent == T.nil:
T.root = y
elif x == x.parent.left:
x.parent.left = y
else:
x.parent.right = y
y.right = x
x.parent = y
13.3插入
红黑树首先是个二叉搜索树,我们可以使用二叉搜索树的insert函数插入元素,然后调用一个执行时间为lgn的方法来维护红黑树的性质。
def RB_INSERT_FIXUP(T, z):
while z.parent.color == COLOR.RED:
if z.parent == z.parent.parent.left:
y = z.parent.parent.right
if y.color == COLOR.RED:
z.parent.color = COLOR.BLACK
y.color = COLOR.BLACK
z.parent.parent.color = COLOR.RED
z = z.parent.parent
else:
if z == z.parent.right:
z = z.parent
LEFT_ROTATE(T, z)
z.parent.color = COLOR.BLACK
z.parent.parent.color = COLOR.RED
RIGHT_ROTATE(T, z.parent.parent)
else:
y = z.parent.parent.left
if y.color == COLOR.RED:
z.parent.color = COLOR.BLACK
y.color = COLOR.BLACK
z.parent.parent.color = COLOR.RED
z = z.parent.parent
else:
if z == z.parent.left:
z = z.parent
RIGHT_ROTATE(T, z)
z.parent.color = COLOR.BLACK
z.parent.parent.color = COLOR.RED
LEFT_ROTATE(T, z.parent.parent)
T.root.color = COLOR.BLACK
def RB_INSERT(T, z):
z.right = T.nil
z.left = T.nil
z.parent = T.nil
y = T.nil
x = T.root
while x != T.nil:
y = x
if z.key < x.key:
x = x.left
else:
x = x.right
z.parent = y
if y == T.nil:
T.root = z
elif z.key < y.key:
y.left = z
else:
y.right = z
z.left = T.nil
z.right = T.nil
z.color = COLOR.RED
RB_INSERT_FIXUP(T, z)
我们使用循环不变式来验证RB_INSERT_FIXUP确实能够保持红黑树的性质在方法中的操作,只会对性质2和性质4有影响(第一次执行完之后只会对性质4有破坏)。消除性质2破坏的主要方法是,将b-r1-r2结构中,保证r2的兄弟节点与r2同色,将r1设为黑色,并b设为红色使得消除在r1-r2间性质4的破坏并使得黑高保持不变,当根节点由红变黑时黑高+1。并对红色节点执行旋转操作时,黑高也不变。
13.4删除
我们先按照删除二叉树节点的方法删除节点,然后维护红黑树的性质。
def TREE_MINIMUM(T, x):
while x.left != T.nil:
x = x.left
return x
def TREE_MAXIMUM(T, x):
while x.right != T.nil:
x = x.right
return x
def RB_TRANSPLANT(T, u, v):
if u.parent == T.nil:
T.root = v
elif u == u.parent.left:
u.parent.left = v
else:
u.parent.right = v
v.parent = u.parent
def RB_DELETE_FIXUP(T, x):
while x != T.root and x.color == COLOR.BLACK:
if x == x.parent.left:
w = x.parent.right
if w.color == COLOR.RED:
w.color = COLOR.BLACK
x.parent.color = COLOR.RED
LEFT_ROTATE(T, x.parent)
w = x.parent.right
if w.left.color == COLOR.BLACK and w.right.color == COLOR.BLACK:
w.color = COLOR.RED
x = x.parent
else:
if w.right.color == COLOR.BLACK:
w.left.color = COLOR.BLACK
w.color = COLOR.RED
RIGHT_ROTATE(T, w)
w = x.parent.right
w.color = x.parent.color
x.parent.color = COLOR.BLACK
w.right.color = COLOR.BLACK
LEFT_ROTATE(T, x.parent)
x = T.root
else:
w = x.parent.left
if w.color == COLOR.RED:
w.color = COLOR.BLACK
x.parent.color = COLOR.RED
RIGHT_ROTATE(T, x.parent)
w = x.parent.left
if w.left.color == COLOR.BLACK and w.right.color == COLOR.BLACK:
w.color = COLOR.RED
x = x.parent
else:
if w.left.color == COLOR.BLACK:
w.right.color = COLOR.BLACK
w.color = COLOR.RED
LEFT_ROTATE(T, w)
w = x.parent.left
w.color = x.parent.color
x.parent.color = COLOR.BLACK
w.left.color = COLOR.BLACK
RIGHT_TOTATE(T, x.parent)
x = T.root
x.color = COLOR.BLACK
def RB_DELETE(T, z):
y = z
y_original_color = y.color
if z.left == T.nil:
x = z.right
RB_TRANSPLANT(T, z, z.right)
elif z.right == T.nil:
x = z.left
RB_TRANSPLANT(T, z, z.left)
else:
y = TREE_MINIMUM(T, z.right)
y_original_color = y.color
x = y.right
if y.parent == z:
x.parent = y
else:
RB_TRANSPLANT(T, y, y.right)
y.right = z.right
y.right.parent = y
RB_TRANSPLANT(T, z, y)
y.left = z.left
y.left.parent = y
y.color = z.color
if y_original_color == COLOR.BLACK:
RB_DELETE_FIXUP(T, x)
在删除节点后,原红黑树的性质可能被改变,如果删除的是红色节点,那么原红黑树的性质依旧保持,此时不用做修正操作,如果删除的节点是黑色节点,原红黑树的性质可能会被改变,我们要对其做修正操作。那么哪些树的性质会发生变化呢,如果删除节点不是树唯一节点,那么删除节点的那一个支的到各叶节点的黑色节点数会发生变化,此时性质5被破坏。如果被删节点的唯一非空子节点是红色,而被删节点的父节点也是红色,那么性质4被破坏。如果被删节点是根节点,而它的唯一非空子节点是红色,则删除后新根节点将变成红色,违背性质2。
我们依然可以通过循环不变式来证明这个修复过程的正确性。
我不太同意书上所谓一重额外黑色的解说。我认为应当着重修复性质5,修复性质5的方法主要通过旋转(在保证其兄弟子树黑高不变的情况下,将兄弟子树的红色节点移到自己这个子树分支上case1 3 4,若兄弟节点和其左右节点均为黑色就将这个性质的破坏向上移动一层 case2)在修复性质5的过程中修复性质4(保证若有两个红的直接连接,染黑其中一个节点同时修复性质5和性质4)。故有以下几种情况: