红黑树的删除

关于红黑树的平衡——删除节点的平衡条件[转载]

网上一直都没有关于删除算法的好文章和实现,在这里记下来,方便日后使用。

删除操作总是在只有一边有孩子的节点或者叶子节点上进行的,绝不会在一个有二个孩子的节点上进行删除操作。而successor函数只有在节点有2个孩子的时候被调用,这个时候,该函数一定是沿节点的右子树向下进行的,最终会找到一个只有一个孩子的节点。

会破坏那些平衡条件

如果删除一个红色的节点,不用做任何操作,红黑树的任何属性都不会被破坏。当删除一个黑色节点的时候,会出现3个问题:

1. 如果删除了根且一个红色的节点做了新的根,则属性1就会被破坏;

2. 该节点的所有祖辈的black height都会少1;

3. 如果该节点的父亲和孩子都是红色的,那么删除这个节点还可能引起连红的情况;

如何恢复平衡

恢复平衡是通过一个函数rb_delete_fixup完成的,以下是完整的算法:

template <class type>
void rb_tree<type>::rb_delete_fixup(node<type> *x) {
    node<type> *w = NULL;

    while ((x != root) && (x->cr == BLACK)) {
        if (x == x->parent->left) {
            w = x->parent->right;
            if (w->cr == RED) {
               // Case 1: w is RED. We change the color of
                // x's parent and w, then perform a left rotate on
                // parent of x, then we can  enter 2, 3 or 4.
                w->cr = BLACK;
                x->parent->cr = RED;
                left_rotate(x->parent);
                w = x->parent->right; // Adjust the w to the new sibling of x
            }
           if ((w->left->cr == BLACK) && (w->right->cr == BLACK)) {
                // Case 2: w is BLACK and both left and right
                // children of w is black
                w->cr = RED;
                x = x->parent; // Shift x up a layer and re-enter the loop
            }
            else if (w->right->cr == BLACK) {
                // Case 3: w is BLACK and the left child of w is RED, the
                // right child of w is BLACK
                w->cr = RED;
                w->left->cr = BLACK;
                right_rotate(w);
                w = w->parent;
            }
            else {
                // Case 4: w is BLACK and the right child of w is RED.
                // After some color change and a left rotation, the tree
                // is balanced again.
                w->cr = w->parent->cr;
                x->parent->cr = BLACK;
                w->right->cr = BLACK;
                left_rotate(x->parent);
                x = root;
            }
        }
        else { // x is right child of its parent
           // Omit for simplicity
        } // End if (x == x->parent->left)
    }
    x->cr = BLACK;
}

整个算法涉及以下几个节点:我们管被删除的节点叫做z,z的successor叫做y(当z只有一个孩子的时候,z和y是相同的,z和y没有在图中表示),y的唯一孩子叫做x,x的父亲叫做p[x],x的兄弟叫做w,如图所示:

clip_image001

整个算法的核心思想:所有的旋转会保持从图中的树根到所有的子节点α、β、γ、δ、ε和ζ的black height相同。那么我们假设x有2层黑色,最后通过颜色的变换和旋转,去掉x的这层额外的黑色,使得红黑树重新平衡。

例如:由于我们假设x2层黑色,从Aαβblack height等于3,执行变换后,从从Aαβblack height仍然等于3

如果根被删除,则肯定是一个新的红色节点充当了新的根,那么rb_delete_fixup会在最后把新根变成黑色,红黑树重新恢复平衡;

如果出现2个红色相连情况,则直接把x染成黑色,红黑树直接恢复平衡;

只有在x不为根,且x的颜色为黑色的时候,才需要通过while循环来恢复红黑树的black height平衡,以及解决连红的问题。从整体上来,算法按照x是p[x]的左/右孩子来分类,每一种分类有4种情况。由于这2种分类是对称的,这里就说一下x是p[x]左孩子的情况。在这种情况下,我们用w的颜色来区分4中情况:

· Case 1:w的颜色是红色的;

clip_image002

把p[x]和w的颜色互换,之后对p[x]左旋。这样D节点就变成了x的新兄弟,由于原来w是红色的,D一定是黑色的,从而进入Case 2、3或4。

· Case 2:w是黑色的,且w的两个孩子也是黑色的(图中的灰色节点为颜色无所谓,下同);

clip_image003

这种情况下,我们把x和w都去掉一层黑色,x变成单黑,w变成红色,这样如果p[x]是黑色,则红黑树重新平衡,如果p[x]是红色,会出现连红的问题,则把x上移一层,重新循环。

· Case 3:w是黑色的,且w的左孩子是红色的,w的右孩子是黑色的;

clip_image004

我们把w和w的左孩子颜色互换,之后对w右旋,从而进入Case 4。

· Case 4:w是黑色的,且w的右孩子是红色的(左孩子是红或黑无所谓);

clip_image005

p[x]和w的颜色互换,w的右孩子染成黑色,之后对p[x]左旋,由于在从根到α、β的路径上多了一个黑节点A,则不再需要x额外的一层黑色,此时红黑树就重新恢复平衡了。

至于x是p[x]的右孩子,情况是完全对称的,这里就不多述了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值