• 算法导论笔记 红黑树(3)


    //---------------------------15/03/20----------------------------

        

        //删除

        

        //相当于copy一个uv

        RB_TRANSPLANT(T,u,v)

        {

            if(u,p == T.nil)

            {

                T.root=v;

            }

            else if(u == u.p.left)

            {

                u.p.left=v;

            }

            else

            {

                u.p.right=v;

            }

            v.p=u.p;

        }

        

        //先做普通的树的删除操作,多加了记录颜色,和判断是否修复的操作

        RB_DELETE(T,z)

        {

           

            y=z;

            y_original_color= y.color;  //记录y原来的颜色

            

            //如果z的儿子小于一个

            if(z.left == T.nil) //没有左儿子,把右儿子赋值给x,让z.right成为z


            {

                x=z.right;

                RB_TRANSPLANT(T,z,z.right);

            }

            else if(z.right == T.nil)   //没有右儿子,做相反的操作

            {

                x = z.left;

                RB_TRANSPLANT(T,z,z.left);

            }

            else                        //有两个儿子

            {

                y=TREE_MINIMUN(z.right);    //找到要移动到z位置的y(min函数可以找到z.right所有子节点中最小的节点

                y_original_color=y.color;

                xy.right;

                if(y.p == z)                //y就是z的右儿子

                {

                    x.p=y;                  //x的父亲是y

                }

                else                    //yz的右儿子的最左下角的节点(最小的节点)

                {

                    RB_TRANSPLANT(T,y,y.right); //y.right成为y

                    y.right=z.right;            //y.right被赋值为z.right

                    y.right.p=y;                //y.right.p(y.right已经是z.right)被赋值为y

                                                //这样zz.right的连线就替换成yy.right(之前的z.right)

                }

                RB_TRANSPLANT(T,z,y);           //这里替换zz.p的连线

                y.left=z.left;

                y.left.p=y;                     //替换和左儿子的连线

                y.color=z.color;                //改变颜色   到此y成功替换掉了z(包括 父亲,儿子,颜色)

            }

            

            if(y_original_color == BLACK)       //如果y原来是黑色的,就要进行修补操作,因为如果y原来是黑色的

                                                //y被提升到z后,原来y的所有子节点的黑高都会少一

            {

                RB_DELETE_FIXUP(T,x);

            }

                

        }

        

        

        RB_DELETE_FIXUP(T,x);

        {

            /*

                首先给x添加一个黑色属性(并不拿来判断,判断还是用原来的属性)

                x是红色时 使x代表红黑(红色才是color属性)  x是黑色时 代表 黑黑

                这么假设是为了让y的黑色属性加到x身上(为了使x底下的节点的黑高都加回一)

                这样当x是红色时(红黑) 只要改变x成黑色就可以使

                xx的所有子节点黑高和原来的一样了.

                如果x已经修补完毕(修补完毕后会有一个操作把x设置为T.root) 或者 x是红色的(只需改变成黑色)

             

            */

            while(x != T.root && x.color == BLACK)

            {

                if(x == x.p.left)

                {

                    //w表示x的兄弟节点

                    w=x.p.right;

                    

                    //case1: w是红色的(说明w的父节点和子节点都是黑色),可以把他转化成case 2 3 4

                    //左转x.p 并调整颜色保持平衡,这时x的父节点就变成红色了。

                    if(w.color == RED)

                    {

                        w.color==BLACK;

                        x.p.color=RED;

                        LEFT_ROTATE(T,x.p);

                        w=x.p.right;

                    }

                    //底下的三种情况w是黑色的

                    

                    /*

                        case2:w的儿子都是黑色

                        xw的黑属性上移( 黑高加1的这个属性赋给x.px还是黑色,w变成红色)

                        这样可以保证x.p这条路径的黑高不变

                        这时x变成了原先的x的父节点,如果x.p是红色那就完成了,否则就开始循环

                    */

                    if(w.left.color == BLACK && w.right.color == BLACK)

                    {

                        w.color= RED;

                        x = x.p;

                    }

                    else

                    {

                        /*

                            case3:w的右儿子是黑色的(这不是我们想要的),那就把他变成红色

                            右转w并重新填颜色(w变成红色,换上来的w的左儿子变成黑色(原本是红色,

                            因为进入case3就说明不可能左右儿子都是黑色,而w的右儿子已经是黑色了)

                            这时候w要再赋值一次,因为w右转下去了,新的w是原来w的左儿子

                        */

                        if(w.right.color == BLACK)

                        {

                            w.left.color = BLACK;

                            w.color=RED;

                            RIGHT_ROTATE(T,w);

                            w= x.p.right;

                        }

                        /*

                            case4:w的右儿子是红色的,此时左转x.p 并改变颜色就完成了(所以要把根节点赋值给x用来判断完成)

                            先左转x.p

                            w的颜色变成原来x.p的颜色,这样右边的路径就相当于去掉了w节点,w本来是黑色的,

                            再把w.right变成黑色(原来是红色),此时右边的路径黑高又加了一。右边已经平衡

                            使x.p的颜色变成黑色(不管原来是什么颜色,这个操作相当于添加一个黑色节点),这样x这边的黑高都加一

                            要使这条路径的黑高不变只需要去掉x的黑高加一属性就好(从黑黑变成黑)

                            x的兄弟节点(原来是w的左儿子)他的上面是一个黑色节点(x.p,他原来上面是w,也是黑色的)再上面是

                            w节点(颜色是原来w.p的颜色)所以这部分黑高不变.所以左边也平衡完成。

                        */

                        w.color=x.p.color;

                        x.p.color=BLACK;

                        w.right.color=BLACK;

                        LEFT_ROTATE(T,x.p);

                        x=T.root;

                    }

                }

                else

                {

                    

                }

            }

            x.color=BLACK;

        }

        

        

        

        

    }

  • 相关阅读:
    TOJ1017: Tour Guide
    tzcacm去年训练的好题的AC代码及题解
    Educational Codeforces Round 40 (Rated for Div. 2)
    AtCoder Regular Contest 092
    浙南联合训练赛20180318
    [Offer收割]编程练习赛50
    牛客练习赛13
    AtCoder Regular Contest 091
    Codeforces Round #470 (rated, Div. 2, based on VK Cup 2018 Round 1)
    csa Round #73 (Div. 2 only)
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983166.html
Copyright © 2020-2023  润新知