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

来源:互联网 发布:棋牌游戏源码可控制 编辑:程序博客网 时间:2024/04/28 19:44

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

    }

    

    

    

    

}

0 0
原创粉丝点击