zoukankan      html  css  js  c++  java
  • 红黑树的实现(二)

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

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

      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;
    }

     附:红黑色实现代码

  • 相关阅读:
    理解JavaScript的数值型数据类型
    The First Article
    DOS符号转义(转 http://www.robvanderwoude.com/escapechars.php)
    symfony中doctrine常用属性
    Node中的promise简说及入门
    DOM操作三
    DOM操作二
    DOM操作一
    JavaScript算法题(二) && 数组filter使用
    简说 call() 、apply() 、bind()
  • 原文地址:https://www.cnblogs.com/chengxuyuancc/p/3010832.html
Copyright © 2011-2022 走看看