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