• 红黑树删除操作


    若被删除的结点有两个非叶子结点,那么可以转换为删除一个“替代点”的问题,该替代点最多只有一个非叶子孩子结点。可以通过前驱或者后继(都最多有一个非叶子孩子结点)来替代最初要被删除的结点,所以下面只关注只有一个非叶子孩子结点的问题,一旦我们解决了这个问题,那么解决方法将同样适用于两种情形:
    1、原本想删除的结点最多有一个非叶子孩子结点
    2、原本想删除的结点有两个非叶子孩子结点(通过前驱和后继可以转化为最多有一个非叶子孩子结点)

    好了,现在用N来表示替代结点(要是被删除的结点没有替代结点,那么N就表示原本要被删除的结点,由红黑树的属性可以推出该结点不可能有孙子结点),替代结点要么是前驱,要么是后继,但是都最多只有一个非叶子孩子结点(程序中使用的是前驱)。结点N为不同颜色时,处理方式不一样,具体如下。

    结点N为红色:

    若结点N为红色,那么它的孩子结点必须是黑色的,而且两个孩子结点都是叶子结点(因为结点N最多只能有一个非叶子孩子结点,所以只能是一边是一个黑色的非叶子孩子结点,另一边是一个黑色叶子结点,这样通过结点N的路径的黑色结点的数目就不一样了(因为黑色的非叶子孩子结点至少有两个黑色叶子结点),这样就违反了性质5)。此时直接将N删除即可,删除之后N被空叶子结点(NULL)替代,而NULL结点都是黑色的,所以属性5依然保持。好了,结点N为红色的情形比较简单,下面看结点N为黑色的情形。

    结点N为黑色:

    结点N为黑色时,可以分为两种情况:
    第1种情况:若其孩子结点M有一个是非叶子结点,另外一个是黑色空叶子结点,那么非叶子结点M必须是红色。因为如果非叶子结点也是黑色的,这样通过结点N的路径的黑色结点的数目将不一样(通过空叶子结点这边的黑色结点的数目是2,而通过黑色非叶子结点这边的至少是3),由此违反了性质5。所以非叶子结点M只能是红色的,这种情况比较简单,只需用M代替N,并将M变为黑色,则不违反任何属性,此时依然是一棵合格的红黑树。

    第2种情况:若两个孩子结点都为空叶子结点(叶子结点都为黑色,并且是NULL),则此时用空叶子结点NULL替代N后,通过原始替代结点N的路径的黑色结点的数目将比原来减少1,此时就要分类讨论了,将替代结点N的父结点表示为P,兄弟结点表示为S。具体分类如下:

    case 1:

    N是根结点,在这种情况下,我们已经做完了(仅仅通过直接返回就可以达到这个效果!),因为这种情况下整棵树只有一个结点(注意大前提:N的两个孩子结点都是空叶子结点,所以整棵树只有一个结点),要删除的结点正是根结点,直接返回之后,在上一层函数中用N的子结点(NULL)替代N,相当于将N删除掉了。

    #294#_     
         |     
         ~317~ 
    
    Deleting key 1th: 294 ---------------------------------------------------------------------
    
    case 0 <294> (若当前结点的子结点为红色,则将子结点变成黑色) : 
    #294#_     
         |     
         #317# 
    
    case 0 <294> (将当前结点用子结点替代,之后释放当前结点) : 
    #317# 
    
    Deleting key 1th: 317 ---------------------------------------------------------------------
    
    case 1 <317> (若当前结点是根结点,直接返回) : 
    case 0 <317> (将当前结点用子结点替代,之后释放当前结点) : 
    NODE is NULL



    注意:在case 2,case 5,case 6中,我们假设N是父结点P的左孩子结点,如果是右孩子结点,那么“左”和“右”应该对调。

    case 2:

    N的兄弟结点S是红色的(从case 3开始S都是黑色的)。此时对调父结点P(肯定是黑色的)和兄弟结点S的颜色,然后将父结点P左旋。注意此时如果直接将N删掉而结束,那么P结点的左边只有一个黑色结点(NULL),而右边有两个黑色结点(S的左孩子和S的孙子结点(黑色的空叶子结点)),这样就违反了属性5,所以左旋之后将接着按case 4、case 5或case 6来处理。

            ________________#177#__________________________                    
            |                                             |                    
       _#103#______                       ________________~265~______          
       |          |                       |                         |          
    #16#         _~146~_             _#206#______                  _#313#_     
                 |     |             |          |                  |     |     
             #140#     #170#     #178#         _~236~_         #294#     #317# 
                                               |     |                         
                                           #208#     #253#                     
    
    Deleting key 1th: 16 ---------------------------------------------------------------------
    
    case 2 <16> (若当前结点的兄弟结点是红色,则将父亲和兄弟的颜色对调,若该结点靠左,则左旋父结点,若靠右则右旋父结点) : 
            ________________#177#__________________________                    
            |                                             |                    
       _~103~______                       ________________~265~______          
       |          |                       |                         |          
    #16#         _#146#_             _#206#______                  _#313#_     
                 |     |             |          |                  |     |     
             #140#     #170#     #178#         _~236~_         #294#     #317# 
                                               |     |                         
                                           #208#     #253#                     
    
    左旋: 103
                      ______#177#__________________________                    
                      |                                   |                    
            ______#146#_                  ________________~265~______          
            |          |                  |                         |          
       _~103~_         #170#         _#206#______                  _#313#_     
       |     |                       |          |                  |     |     
    #16#     #140#               #178#         _~236~_         #294#     #317# 
                                               |     |                         
                                           #208#     #253#                     
    
    case 4 <16> (若当前结点的父结点为红色,兄弟结点是黑色,且兄弟结点的左右子结点都为黑色,则将兄弟结点和父结点的颜色对调) : 
                      ______#177#__________________________                    
                      |                                   |                    
            ______#146#_                  ________________~265~______          
            |          |                  |                         |          
       _#103#_         #170#         _#206#______                  _#313#_     
       |     |                       |          |                  |     |     
    #16#     ~140~               #178#         _~236~_         #294#     #317# 
                                               |     |                         
                                           #208#     #253#                     
    
    case 0 <16> (将当前结点用子结点替代,之后释放当前结点) : 
                  ______#177#__________________________                    
                  |                                   |                    
        ______#146#_                  ________________~265~______          
        |          |                  |                         |          
    #103#_         #170#         _#206#______                  _#313#_     
         |                       |          |                  |     |     
         ~140~               #178#         _~236~_         #294#     #317# 
                                           |     |                         
                                       #208#     #253#                     



    case 3:

    结点N的父结点P,兄弟结点S以及S的孩子结点都是黑色的。此时简单的将S设为红色,这样做可以让通过S的所有路径都少一个黑色节点,与通过N的路径的黑色结点就相同了。但是,通过P的所有路径现在比不通过P的路径少了一个黑色节点,所以仍然违反性质5。要修正这个问题,我们要从case 1开始,在P上做重新平衡处理,并且一直递归到根结点为止,到根结点时,通过根结点的所有路径都少了一个黑色结点,然后再从case 1返回。

             ______#236#______          
             |               |          
        _#178#_             _#294#_     
        |     |             |     |     
    #177#     #206#     #253#     #317# 
    
    Deleting key 5th: 253 ---------------------------------------------------------------------
    
    case 3 <253> (若当前结点的父结点和兄弟结点是黑色,且兄弟结点的左右子结点都为黑色,则将兄弟结点变红,将父结点转到case 1做重新平衡处理) : 
             ______#236#______          
             |               |          
        _#178#_             _#294#_     
        |     |             |     |     
    #177#     #206#     #253#     ~317~ 
    
    case 3 <294> (若当前结点的父结点和兄弟结点是黑色,且兄弟结点的左右子结点都为黑色,则将兄弟结点变红,将父结点转到case 1做重新平衡处理) : 
             ______#236#______          
             |               |          
        _~178~_             _#294#_     
        |     |             |     |     
    #177#     #206#     #253#     ~317~ 
    
    case 1 <236> (若当前结点是根结点,直接返回) : 
    case 0 <253> (将当前结点用子结点替代,之后释放当前结点) : 
             ______#236#_          
             |          |          
        _~178~_         #294#_     
        |     |              |     
    #177#     #206#          ~317~ 



    case 4:

    结点N的父结点P是红色的,兄弟结点S以及S的两个孩子结点(都是空叶子结点)都是黑色。此时将P和S的颜色对调,这不影响通过S的黑色结点数量,但是在通过N的路径上增加了一个黑色结点,正好和要删除的结点N相抵消,这样属性5被满足了。

                  ________________#236#______          
                  |                         |          
        ______#177#______                  _#294#_     
        |               |                  |     |     
    #146#_             _~206~_         #253#     #317# 
         |             |     |                         
         ~170~     #178#     #208#                     
    
    Deleting key 6th: 208 ---------------------------------------------------------------------
    
    case 4 <208> (若当前结点的父结点为红色,兄弟结点是黑色,且兄弟结点的左右子结点都为黑色,则将兄弟结点和父结点的颜色对调) : 
                  ________________#236#______          
                  |                         |          
        ______#177#______                  _#294#_     
        |               |                  |     |     
    #146#_             _#206#_         #253#     #317# 
         |             |     |                         
         ~170~     ~178~     #208#                     
    
    case 0 <208> (将当前结点用子结点替代,之后释放当前结点) : 
                  ___________#236#______          
                  |                    |          
        ______#177#______             _#294#_     
        |               |             |     |     
    #146#_             _#206#     #253#     #317# 
         |             |                          
         ~170~     ~178~                          




    case 5:

    结点N的兄弟结点S的左孩子是红色,右孩子是黑色(左红右黑),并且结点N是父结点P的左孩子。此时将S与其左孩子的颜色对调,然后右旋S。注意此时通过父结点P的路径都有相同的黑色结点数目,但是如果直接将N删掉会违反属性5(与case 2中类似),所以我们继续按照case 6来处理。

             ___________#236#______          
             |                    |          
        _#177#______             _#294#_     
        |          |             |     |     
    #170#         _#206#     #253#     #317# 
                  |                          
              ~178~                          
    
    Deleting key 1th: 170 ---------------------------------------------------------------------
    
    case 5 <170> (subcase1: 若当前结点为左子结点,兄弟结点是黑色,且兄弟结点的左子结点为红色,右子结点为黑色,则将兄弟结点和兄弟结点左孩子的颜色对调,再右旋兄弟结点) : 
             ___________#236#______          
             |                    |          
        _#177#______             _#294#_     
        |          |             |     |     
    #170#         _~206~     #253#     #317# 
                  |                          
              #178#                          
    
    右旋: 206
             ___________#236#______          
             |                    |          
        _#177#_                  _#294#_     
        |     |                  |     |     
    #170#     #178#_         #253#     #317# 
                   |                         
                   ~206~                     
    
    case 6 <170> (将兄弟结点的颜色和父结点的颜色对调) : 
             ___________#236#______          
             |                    |          
        _#177#_                  _#294#_     
        |     |                  |     |     
    #170#     #178#_         #253#     #317# 
                   |                         
                   ~206~                     
    
    case 6 <170> (subcase1: 若当前结点为左子结点,则兄弟结点的右子结点必为红色,将兄弟结点的右子结点变成黑色,将父结点左旋) : 
             ___________#236#______          
             |                    |          
        _#177#_                  _#294#_     
        |     |                  |     |     
    #170#     #178#_         #253#     #317# 
                   |                         
                   #206#                     
    
    左旋: 177
                  ______#236#______          
                  |               |          
             _#178#_             _#294#_     
             |     |             |     |     
        _#177#     #206#     #253#     #317# 
        |                                    
    #170#                                    
    
    case 0 <170> (将当前结点用子结点替代,之后释放当前结点) : 
             ______#236#______          
             |               |          
        _#178#_             _#294#_     
        |     |             |     |     
    #177#     #206#     #253#     #317# 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                  ________________~265~______          
        |     |                  |                         |          
    #103#     #170#         _#206#______                  _#313#_     
                            |          |                  |     |     
                        #178#         _~236~_         #294#     #317# 
                                      |     |                         
                                  #208#     #253#                     
    
    Deleting key 12th: 313 ---------------------------------------------------------------------
    
    若结点有两个非空结点,用前驱代替它
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                  ________________~265~______          
        |     |                  |                         |          
    #103#     #170#         _#206#______                  _#294#_     
                            |          |                  |     |     
                        #178#         _~236~_         #294#     #317# 
                                      |     |                         
                                  #208#     #253#                     
    
    case 3 <294> (若当前结点的父结点和兄弟结点是黑色,且兄弟结点的左右子结点都为黑色,则将兄弟结点变红,将父结点转到case 1做重新平衡处理) : 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                  ________________~265~______          
        |     |                  |                         |          
    #103#     #170#         _#206#______                  _#294#_     
                            |          |                  |     |     
                        #178#         _~236~_         #294#     ~317~ 
                                      |     |                         
                                  #208#     #253#                     
    
    case 5 <294> (subcase2: 若当前结点为右子结点,兄弟结点是黑色,且兄弟结点的左子结点为黑色,右子结点为红色,则将兄弟结点和兄弟结点右孩子的颜色对调,再左旋兄弟结点) : 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                  ________________~265~______          
        |     |                  |                         |          
    #103#     #170#         _~206~______                  _#294#_     
                            |          |                  |     |     
                        #178#         _#236#_         #294#     ~317~ 
                                      |     |                         
                                  #208#     #253#                     
    
    左旋: 206
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                            ______~265~______          
        |     |                            |               |          
    #103#     #170#              ______#236#_             _#294#_     
                                 |          |             |     |     
                            _~206~_         #253#     #294#     ~317~ 
                            |     |                                   
                        #178#     #208#                               
    
    case 6 <294> (将兄弟结点的颜色和父结点的颜色对调) : 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                            ______#265#______          
        |     |                            |               |          
    #103#     #170#              ______~236~_             _#294#_     
                                 |          |             |     |     
                            _~206~_         #253#     #294#     ~317~ 
                            |     |                                   
                        #178#     #208#                               
    
    case 6 <294> (subcase2: 若当前结点为右子结点,则兄弟结点的左子结点必为红色,将兄弟结点的左子结点变成黑色,将父结点右旋) : 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                            ______#265#______          
        |     |                            |               |          
    #103#     #170#              ______~236~_             _#294#_     
                                 |          |             |     |     
                            _#206#_         #253#     #294#     ~317~ 
                            |     |                                   
                        #178#     #208#                               
    
    右旋: 265
             ______#177#________________                              
             |                         |                              
        _#146#_                  ______~236~______                    
        |     |                  |               |                    
    #103#     #170#         _#206#_             _#265#______          
                            |     |             |          |          
                        #178#     #208#     #253#         _#294#_     
                                                          |     |     
                                                      #294#     ~317~ 
    
    case 0 <294> (将当前结点用子结点替代,之后释放当前结点) : 
             ______#177#________________                         
             |                         |                         
        _#146#_                  ______~236~______               
        |     |                  |               |               
    #103#     #170#         _#206#_             _#265#_          
                            |     |             |     |          
                        #178#     #208#     #253#     #294#_     
                                                           |     
                                                           ~317~ 



    case 6:

    结点N的兄弟结点S是黑色的,S的右孩子是红色的(右红),并且结点N是父结点P的左孩子。此时将父结点P和兄弟结点S的颜色对调,再将S的右孩子变为黑色,然后左旋父结点P。
     

                ________________#177#__________________________                         
                |                                             |                         
       _____#103#______                       ________________~265~______               
       |              |                       |                         |               
    #15#_            _~146~_             _#206#______                  _#294#_          
        |            |     |             |          |                  |     |          
        ~16~     #140#     #170#     #178#         _~236~_         #293#     #313#_     
                                                   |     |                        |     
                                               #208#     #253#                    ~317~ 
    
    Deleting key 14th: 293 ---------------------------------------------------------------------
    
    case 6 <293> (将兄弟结点的颜色和父结点的颜色对调) : 
                ________________#177#__________________________                         
                |                                             |                         
       _____#103#______                       ________________~265~______               
       |              |                       |                         |               
    #15#_            _~146~_             _#206#______                  _#294#_          
        |            |     |             |          |                  |     |          
        ~16~     #140#     #170#     #178#         _~236~_         #293#     #313#_     
                                                   |     |                        |     
                                               #208#     #253#                    ~317~ 
    
    case 6 <293> (subcase1: 若当前结点为左子结点,则兄弟结点的右子结点必为红色,将兄弟结点的右子结点变成黑色,将父结点左旋) : 
                ________________#177#__________________________                         
                |                                             |                         
       _____#103#______                       ________________~265~______               
       |              |                       |                         |               
    #15#_            _~146~_             _#206#______                  _#294#_          
        |            |     |             |          |                  |     |          
        ~16~     #140#     #170#     #178#         _~236~_         #293#     #313#_     
                                                   |     |                        |     
                                               #208#     #253#                    #317# 
    
    左旋: 294
                ________________#177#__________________________                         
                |                                             |                         
       _____#103#______                       ________________~265~___________          
       |              |                       |                              |          
    #15#_            _~146~_             _#206#______                       _#313#_     
        |            |     |             |          |                       |     |     
        ~16~     #140#     #170#     #178#         _~236~_             _#294#     #317# 
                                                   |     |             |                
                                               #208#     #253#     #293#                
    
    case 0 <293> (将当前结点用子结点替代,之后释放当前结点) : 
                ________________#177#__________________________                    
                |                                             |                    
       _____#103#______                       ________________~265~______          
       |              |                       |                         |          
    #15#_            _~146~_             _#206#______                  _#313#_     
        |            |     |             |          |                  |     |     
        ~16~     #140#     #170#     #178#         _~236~_         #294#     #317# 
                                                   |     |                         
                                               #208#     #253#                     
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                  ________________~265~______          
        |     |                  |                         |          
    #103#     #170#         _#206#______                  _#313#_     
                            |          |                  |     |     
                        #178#         _~236~_         #294#     #317# 
                                      |     |                         
                                  #208#     #253#                     
    
    Deleting key 12th: 313 ---------------------------------------------------------------------
    
    若结点有两个非空结点,用前驱代替它
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                  ________________~265~______          
        |     |                  |                         |          
    #103#     #170#         _#206#______                  _#294#_     
                            |          |                  |     |     
                        #178#         _~236~_         #294#     #317# 
                                      |     |                         
                                  #208#     #253#                     
    
    case 3 <294> (若当前结点的父结点和兄弟结点是黑色,且兄弟结点的左右子结点都为黑色,则将兄弟结点变红,将父结点转到case 1做重新平衡处理) : 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                  ________________~265~______          
        |     |                  |                         |          
    #103#     #170#         _#206#______                  _#294#_     
                            |          |                  |     |     
                        #178#         _~236~_         #294#     ~317~ 
                                      |     |                         
                                  #208#     #253#                     
    
    case 5 <294> (subcase2: 若当前结点为右子结点,兄弟结点是黑色,且兄弟结点的左子结点为黑色,右子结点为红色,则将兄弟结点和兄弟结点右孩子的颜色对调,再左旋兄弟结点) : 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                  ________________~265~______          
        |     |                  |                         |          
    #103#     #170#         _~206~______                  _#294#_     
                            |          |                  |     |     
                        #178#         _#236#_         #294#     ~317~ 
                                      |     |                         
                                  #208#     #253#                     
    
    左旋: 206
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                            ______~265~______          
        |     |                            |               |          
    #103#     #170#              ______#236#_             _#294#_     
                                 |          |             |     |     
                            _~206~_         #253#     #294#     ~317~ 
                            |     |                                   
                        #178#     #208#                               
    
    case 6 <294> (将兄弟结点的颜色和父结点的颜色对调) : 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                            ______#265#______          
        |     |                            |               |          
    #103#     #170#              ______~236~_             _#294#_     
                                 |          |             |     |     
                            _~206~_         #253#     #294#     ~317~ 
                            |     |                                   
                        #178#     #208#                               
    
    case 6 <294> (subcase2: 若当前结点为右子结点,则兄弟结点的左子结点必为红色,将兄弟结点的左子结点变成黑色,将父结点右旋) : 
             ______#177#__________________________                    
             |                                   |                    
        _#146#_                            ______#265#______          
        |     |                            |               |          
    #103#     #170#              ______~236~_             _#294#_     
                                 |          |             |     |     
                            _#206#_         #253#     #294#     ~317~ 
                            |     |                                   
                        #178#     #208#                               
    
    右旋: 265
             ______#177#________________                              
             |                         |                              
        _#146#_                  ______~236~______                    
        |     |                  |               |                    
    #103#     #170#         _#206#_             _#265#______          
                            |     |             |          |          
                        #178#     #208#     #253#         _#294#_     
                                                          |     |     
                                                      #294#     ~317~ 
    
    case 0 <294> (将当前结点用子结点替代,之后释放当前结点) : 
             ______#177#________________                         
             |                         |                         
        _#146#_                  ______~236~______               
        |     |                  |               |               
    #103#     #170#         _#206#_             _#265#_          
                            |     |             |     |          
                        #178#     #208#     #253#     #294#_     
                                                           |     
                                                           ~317~ 

    去吧,去吧,到彼岸去吧,彼岸是光明的世界!
  • 相关阅读:
    poj 2777 Count Color
    poj 3264 Balanced Lineup
    hdu 1754 I hate it
    poj 3468 A Simple Problem with Integers
    noip 2013 提高组 Day2 部分题解
    [c/c++]指针(2)
    [c/c++]指针(1)
    vijos 1360 八数码问题
    [复习]快速幂算法
    noip 2013 提高组 day1
  • 原文地址:https://www.cnblogs.com/lengyue365/p/5140831.html
Copyright © 2020-2023  润新知