• 算法导论笔记:13-02红黑树插入


           红黑树的插入可在O(lg n)完成,红黑树的插入类似于二叉搜索树的插入,为了尽量维护红黑树的性质,将插入的新节点标记为RED,然后调用RB-INSERT-FIXUP对红黑树的性质进行维护,RB-INSERT代码如下:

     

    RB-INSERT(T,z)        

           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.p = y   

                

           if y == T.nil          

                 T.root= z            

          else  if  z.key < y.key  

                 y.left= z            

          else  y.right = z  

       

          z.left = T.nil        

          z.right = T.nil       

          z.color = RED     

       

           RB-INSERT-FIXUP(T, z) 

     

           RB-INSERT-FIXUP负责在插入之后,维护红黑树的性质,代码如下:

    RB-INSERT-FIXUP(T,z)                

           while z.p.color == RED               

                  if z.p == z.p.p. left                

                         y = z.p.p.right                      

                         if y.color == RED                    

                                z.p.color = BLACK                   // case 1          

                                y.color = BLACK                      // case 1            

                                z.p.p.color = RED                    // case 1          

                                z = z.p.p                                  // case 1  

                         else 

                                if z == z.p.right               

                                      z= z.p                                             //case 3                   

                                      LEFT-ROTATE(T,z)                      // case 3   

         

                               z.p.color= BLACK                             // case 2         

                               z.p.p.color= RED                              // case 2         

                               RIGHT-ROTATE(T,z.p.p)                 // case 2    

                 else(same as then clause with “right” and “left” exchanged)

                         y = z.p.p.left                      

                         if y.color == RED                     

                                z.p.color = BLACK                    // case 1          

                                y.color = BLACK                       // case 1            

                                z.p.p.color = RED                    // case 1          

                                z = z.p.p                                  // case 1  

                         else 

                                if z == z.p.left               

                                      z = z.p                                          //case 3                   

                                      RIGHT-ROTATE(T,z)                 // case 3   

         

                               z.p.color= BLACK                          // case2         

                               z.p.p.color= RED                           // case2         

                               LEFT-ROTATE(T,z.p.p)                    // case 2 

     T.root.color = BLACK                

     

           对于新插入的结点z来说,因z的颜色为红色,所以,性质1,3,5都不会早到破坏,性质2,4有可能被破坏。如果z是根节点,则破坏了性质2,如果z的父节点为红色,则破坏了性质4。如果z的父节点z.p为黑色的话,则红黑树的性质没有发生改变。若z为根节点,则直接置rootcolorBLACK即可。所以只考虑z的父节点为RED的情况。

     

           根据z的父节点是左孩子或者右孩子的处理方法是对称的,所以只考虑z的父节点是左孩子的情况(if z.p == z.p.p. left)。根据z的叔叔结点y的颜色不同,以及z所处的位置,分为以下三种情况:

     

    1:z的叔叔结点y的颜色为RED,记为case1:

           这种情况,不管z是左孩子,还是右孩子,都是同样的处理方法:

    z是右孩子

    z是左孩子。

           这种情况的处理代码是:

                                z.p.color = BLACK                   // case 1          

                                y.color = BLACK                       // case 1            

                                z.p.p.color = RED                    // case 1          

                                z = z.p.p                                  // case 1  

           得到下面的图:

    z是右孩子

    z是左孩子

     

         这种情况就是把z的父节点和叔叔结点y都变成BLACK,然后z的祖父结点变为RED,然后使祖父结点成为新的z,继续向上处理。

           这种处理方式,各个分支的黑高没有发生变化,同时维护了原红色z的父节点为BLACK的性质。

           这样处理之后,可以转变为剩下的情况2或者3的一种:

     

    2:z的叔叔结点y的颜色为BLACK,z为左孩子,记为case2:

           这种情况下, 因为z的父节点是RED,所以z的祖父节点是BLACK,如下图:

           这种情况下的调整代码为:

                         z.p.color = BLACK                          // case 2         

                        z.p.p.color= RED                           // case 2         

                        RIGHT-ROTATE(T,z.p.p)  

           将z的父节点变为BLACK,祖父节点变为RED,同时对祖父节点进行右旋,得到下面的图:

           这种情况下,整个分支的黑高保持不变,同时内部分支的黑高也维持了性质5。同时,z的父节点不再是RED,所以退出循环。


    3:z的叔叔结点y的颜色为BLACK,z为右孩子,记为case3:

           这种情况与case2类似,如下图;

           这种情况下的调整代码为:

                                z = z.p                                      // case 3                   

                               LEFT-ROTATE(T, z)                    // case 3 

    调整后得到下面的图:

           调整后,各个分支的黑高没有发生任何变化,同时,变成了与case2吻合的情况。

     

    分析:

           n个结点的红黑树高度为O(lg n),插入操作中,除了最后一步外,剩下的操作与二叉搜索树的插入相同,也就是时间复杂度为O(lg n)。在RD-INSERT-FIXUP中,仅当case1时,z才沿着树上升,while循环才会重复执行。所以while的重复次数为O(lgn)如果是case2或者3,则while循环直接结束。所以,RB-INSERT的时间复杂度为O(lg n)

  • 相关阅读:
    linux系统命令学习系列-用户切换命令su,sudo
    linux系统命令学习系列-用户组管理
    linux系统命令学习-用户管理
    python web开发-flask中sqlalchemy的使用
    python web开发-flask连接sqlite数据库
    python实现bt种子 torrent转magnet
    prefProvider.kt
    douyin-bot-代码
    pyadb关于python操作adb的资料
    bottle源码
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247233.html
Copyright © 2020-2023  润新知