算法导论 第十三章 红黑树

本文介绍了红黑树的基本性质,包括红黑树是二叉搜索树,确保任意路径不会比其他路径长出2倍。红黑树的search、minimum、maximum等操作可在O(lgn)时间内完成。文章还讨论了红黑树的旋转操作,分为左旋和右旋,用于保持二叉搜索树性质不变。在删除节点时,需要维护红黑树的性质,尤其是当删除黑色节点时,可能需要进行修正操作,这些操作通常涉及旋转和颜色调整。
摘要由CSDN通过智能技术生成

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)。故有以下几种情况:





习题解答




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值