算法导论笔记 红黑树(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;
}
}
//删除
//相当于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;
}
}
相关文章推荐
- 算法导论学习笔记(6)——红黑树
- 《算法导论》笔记--红黑树(二)
- 算法导论学习笔记——红黑树
- 《算法导论》第13章 红黑树 个人笔记
- 算法导论笔记:13-03红黑树删除
- 算法导论学习笔记(九):红黑树
- 《算法导论》笔记(5)链表到红黑树
- 算法导论学习笔记-第十三章-红黑树
- 《算法导论》笔记--红黑树(二)
- 算法导论笔记 红黑树(3)
- 《算法导论》笔记--红黑树(一)
- 红黑树--删除 算法导论笔记
- 算法导论笔记 红黑树(1)
- 算法导论笔记:13-02红黑树插入
- 《算法导论》笔记 第13章 13.1 红黑树的性质
- 算法导论笔记 红黑树(1)
- 《算法导论》笔记--红黑树(一)
- 《算法导论》笔记 第13章 13.1 红黑树的性质
- 算法导论笔记:13-01红黑树概念与基本操作
- 《算法导论》笔记(6)链表到红黑树 部分习题