您的位置:首页 > 其它

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

2015-03-21 15:57 316 查看
//---------------------------15/03/20----------------------------



//删除



//相当于copy一个u给v
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;
x=y.right;

if(y.p == z)
//y就是z的右儿子
{
x.p=y;
//x的父亲是y
}

else
//y是z的右儿子的最左下角的节点(最小的节点)
{
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

//这样z和z.right的连线就替换成y和y.right(之前的z.right)
}
RB_TRANSPLANT(T,z,y);
//这里替换z和z.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成黑色就可以使

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

如果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的儿子都是黑色

把x和w的黑属性上移(把
黑高加1的这个属性赋给x.p,x还是黑色,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;
}








}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: