红黑树的实现(二)

  红黑树的定义和插入在红黑树的实现(一)中已经描述和实现了,下面说一下红黑树的删除。

  红黑树的删除也包括两个步骤:

  1.删除结点

  2.调整树满足红黑树的定义

  首先是删除一个结点,同样可以按二叉排序树的删除结点来删除。删除结点又分为4中情况:

  (1)删除结点没有左孩子,有右孩子

  (2)删除结点没有右孩子,有左孩子

  (3)删除结点为叶子结点

  (4)删除结点既有左孩子又有右孩子

  对于情况(1),可以直接用右孩子代替删除的结点,并且由于删除结点有右孩子,所以删除结点必定为黑色,右孩子必定为红色(假设删除结点为红色,右孩子必定为黑色,这样是违反红黑树定义4的,所以删除结点必定为黑色,同理右孩子必定为红色),因此只要把右孩子着为黑色,红黑树依然没有违反定义。对于情况(2),与情况(1)相同,只是把右孩子换成左孩子。对于情况(3),可以直接删除结点,不过如果该删除的结点为黑色,删除后会违反定义4,所以必须进行调整。对于情况(4),可以转换为前三种情况,因为可以用删除结点在中序排序中的后继结点代替该删除结点,相当于删除的是后继结点,而后继结点属于前面三种情况的一种。代码如下:

 1 rb_node_t *rb_erase_node(rb_node_t *node, rb_node_t **root)
 2 {
 3     rb_node_t *replace, *p;
 4 
 5     if (NULL == node)
 6         return NULL;
 7     if (NULL == node->lchild)
 8     {
 9         /*左孩子为空,直接用右孩子代替node*/    
10         replace = node->rchild;
11         p = node->parent;
12         if (replace)
13         {
14             replace->parent = p;
15             replace->color = BLACK;
16         }
17         else if (BLACK == node->color)
18             rb_erase_fix_node(node, root);/*注意这里*/
19         if (NULL == p)
20             *root = replace;
21         else if (node == p->lchild)
22             p->lchild = replace;
23         else
24             p->rchild = replace;
25     }
26     else if (NULL == node->rchild)
27     {
28         /*右孩子为空,且左孩子不为空*/    
29         replace = node->lchild;
30         p = node->parent;
31         replace->parent = p;
32         replace->color = BLACK;
33         rebalance = NULL;
34         if (NULL == p)
35             *root = replace;
36         else if (node == p->lchild)
37             p->lchild = replace;
38         else
39             p->rchild = replace;
40     }
41     else 
42     {
43         /*左右孩子均不为空*/
44         replace = rb_next(node);
45         key_copy(node, replace);        
46         info_copy(node, replace);
47         node = replace;
48         /*左孩子为空*/
49         replace = node->rchild;
50         p = node->parent;
51         if (replace)
52         {
53             replace->parent = p;
54             replace->color = BLACK;
55         }
56         else if (BLACK == node->color)
57             rb_erase_fix_node(node, root);/*注意这里*/
58         if (node == p->lchild)
59             p->lchild = replace;
60         else
61             p->rchild = replace;
62     }
63     return node;
64 }

  现在我们来看调整。删除结点后真正需要调整的是遇到情况3,想想删除一个结点会违反红黑树的哪些定义呢?很有很能是违反第4条定义,因为可能会删除一个颜色为黑色的结点。红黑树的调整总共包括8种情况,和插入调整情况一样,其实就是4种,另外四种都是对称的,这里就只讨论删除结点为父结点左孩子的情况,将删除结点作为调整结点。情况(1)调整结点的兄弟为红色,那么父结点必定为黑色,将父结点设置为红色,兄弟结点设置为黑色,左旋父结点,这样就转化为了情况2;情况(2)调整结点的兄弟为黑色。情况(2)中可以分成三种情况讨论,即情况(2-1)兄弟结点的左右孩子均为黑色,这种情况可以直接设置兄弟结点颜色为红色,将调整结点设置为父亲结点;情况(2-2)兄弟结点的左孩子为红色,右孩子为黑色,将兄弟结点设置为红色,兄弟结点的左孩子设置为黑色,右旋兄弟结点转换为情况(2-3);兄弟结点的右孩子为红色,将兄弟结点的右孩子设置为黑色,兄弟结点的颜色设置为父结点的颜色,父结点设置为黑色,左旋父结点,这样就已经调整好了。这里要注意的就是调整完之后要将删除结点彻底的从树中删除,调整时由于调整的需要,并没有把结点从树上删除(算法导论用了一个叫NIL的结点作为了替代,所以直接删除了结点,这是实现细节,对于理解整个的调整没有什么影响的);还有就是如果兄弟结点的孩子右不错字的情况,要特别小心,自己就是没有考虑全部的情况,所以总是段错误,后来调试发现是空指针异常了

static void rb_erase_fix_node(rb_node_t *node, rb_node_t **root)
{
    rb_node_t *p, *s, *sl, *sr;

    while (node != *root && node->color == BLACK)
    {
        p = node->parent;
        if (node == p->lchild)    
        {
            /*node为左孩子*/    
            s = p->rchild;/*s必定不为空*/
            if (RED == s->color)
            {
                /*情况1:node的兄弟为红色,设置p为红色,s为黑色,左旋p,转换为情况2
                 *      P           S
                 *     / \         / \
                 *    n?  s -->   p   SR
                 *       / \     / \
                 *      SL  SR  n?  SL
                 *      */
                p->color = RED;
                s->color = BLACK;
                rb_rotate_left(p, s);
                if (NULL == s->parent)
                    *root = s;
            }
            else 
            {
                sl = s->lchild;
                sr = s->rchild;
                if (NULL == sl && NULL == sr || sl && BLACK == sl->color && sr && BLACK == sr->color)
                {
                    /*情况2:node的兄弟为黑色,设置s设为红色,node设置为p
                     *      p?         p?
                     *     / \        / \
                     *    n?  S -->  n?  s
                     *       / \        / \
                     *      SL SR      SL SR
                     *      */
                    s->color = RED;
                    node = p;
                }
                else if ((NULL == sr || sr && BLACK == sr->color) && sl && RED == sl->color)
                {    
                    /*情况3:node的兄弟的右孩子为黑色,左孩子为红色,设置sl设为黑色,s设置为红色,右旋s
                     *      p?         p?
                     *     / \        / \
                     *    n?  S -->  n?  SL
                     *       / \          \
                     *      sl SR          s
                     *                      \
                     *                       SR
                     *      */
                    sl->color = BLACK;
                    s->color = RED;
                    rb_rotate_right(s, sl);
                    if (NULL == sl->parent)
                        *root = sl;
                }
                else
                {
                    /*情况4:node的兄弟的右孩子为红色,设置sr设为黑色,s设置为p的颜色,p设置为黑色,左旋p
                     *      p?         s? 
                     *     / \        / \
                     *    n?  S -->  P      SR 
                     *         \    /      
                     *         sr  n?      
                     *      */
                    sr->color = BLACK;
                    s->color = p->color;
                    p->color = BLACK;
                    rb_rotate_left(p, s);
                    if (NULL == s->parent)    
                        *root = s;
                    node = *root;
                }
            }
        }
        else
        {
            /*node为右孩子*/    
            s = p->lchild;/*s必定不为空*/
            if (RED == s->color)
            {
                /*情况1:node的兄弟为红色,设置p为红色,s为黑色,右旋p,转换为情况2
                 *      P           S
                 *     / \         / \
                 *    s   n? -->  p  SR
                 *   / \             / \
                 *  SL  SR          SR  n? 
                 *      */
                p->color = RED;
                s->color = BLACK;
                rb_rotate_right(p, s);
                if (NULL == s->parent)
                    *root = s;
            }
            else 
            {
                sl = s->lchild;
                sr = s->rchild;
                if (NULL == sl && NULL == sr || sl && BLACK == sl->color && sr && BLACK == sr->color)
                {
                    /*情况2:node的兄弟的两个孩子均为黑色,设置s设为红色,node设置为p
                     *      p?         p?
                     *     / \        / \
                     *    S   n? --> s   n? 
                     *   / \        / \
                     *  SL SR      SL SR
                     *      */
                    s->color = RED;
                    node = p;
                }
                else if ((NULL == sl || sl && BLACK == sl->color) && sr && RED == sr->color)
                {    
                    /*情况3:node的兄弟的左孩子为黑色,右孩子为红色,设置sr设为黑色,s设置为红色,左旋s
                     *      p?         p?
                     *     / \        / \
                     *    S   n? --> SR  n? 
                     *   / \        / 
                     *  SL  sr     s   
                     *            /     
                     *           SL       
                     *      */
                    sr->color = BLACK;
                    s->color = RED;
                    rb_rotate_left(s, sr);
                    if (NULL == sr->parent)
                        *root = sr;
                }
                else
                {
                    /*情况4:node的兄弟的左孩子为红色,设置sl设为黑色,s设置为p的颜色,p设置为黑色,右旋p
                     *      p?         s? 
                     *     / \        / \
                     *    S  n? -->  SL  P 
                     *   /                \       
                     *  sl                n? 
                     *      */
                    sl->color = BLACK;
                    s->color = p->color;
                    p->color = BLACK;
                    rb_rotate_right(p, s);
                    if (NULL == s->parent)    
                        *root = s;
                    node = *root;
                }
            }

        }
    }
    node->color = BLACK;
}

 附:红黑色实现代码

原文地址:https://www.cnblogs.com/chengxuyuancc/p/3010832.html