您的位置:首页 > 其它

算法导论笔记:13-03红黑树删除

2015-04-26 18:11 323 查看
红黑树的删除操作花费O(lg n)时间,删除算法与二叉搜索树的删除类似,首先红黑树的TRANSPLANT版本有些许不同,主要是因为红黑树使用nil结点代替NULL指针造成的:
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

if z.left == T.nil

x = z.right

RB-TRANSPLAN(T, z, z.right)



else if z.right == T.nil

x = z.left

RB-TRANSPLAN(T, z, z.left)



else y = TREE-MINIMUM(z.right)

y-original-color= y.color

x= y.right

if y.p == z

x.p= y


else RB-TRANSPLANT(T, y, y.right)

y.right= z.right

y.right.p= y

RB-TRANSPLANT(T,z, y)

y.left = z.left

y.left.p= y

y.color= z.color



if y-original-color == BLACK

RB-DELETE-FIXUP(T.x)




调整代码如下:

RB-DELETE-FIXUP(T, x)

while x != T.root and x.color == BLACK

if x == x.p. left

w = x.p.right

if w.color == RED

w.color =BLACK // case 1

x.p.color =RED // case 1

LEFT-ROTATE(T,x.p) // case 1

w = x.p.right // case1



if w.left.color ==BLACK and w.right.color == BLACK

w.color= RED //case 2

x= x.p //case 2



else if w.right.color == BLACK

w.left.color = BLACK // case 4

w.color = RED // case 4

RIGHT-ROTATE(T,w) // case 4

w = x.p.right // case 4



w.color = x.p.color // case 3

x.p.color = BLACK // case 3

w.right.color = BLACK // case 3

LEFT-ROTATE(T, x.p) // case 3

x = T.root // case 3



else(same as then clause with “right” and “left” exchanged)

......

x.color= BLACK



根据代码,可以将删除操作分为四种情况(等同于二叉搜索树的删除),代码中的x, y, z的意思如下:

z表示要删除的元素;

y表示实际要删除的元素,对于前两种情况(z只有一个孩子),y就是z;对于后两种情况(z有俩孩子),y是z的后继元素。

x表示删除y之后,代替y所在位置的元素。

具体情况如下图, :







情况一,二很简单,不再赘述,对于情况三和四,表面上看好像是删除了结点z,实际上是删除了结点y,因为在结点z的位置上,下面的代码保证了:除了z.key变成了y.key,其他的属性left,
right, p, color都没有发生实质的变化。
所以,在红黑树中,实际上是删除了结点y,而结点x则成为在y所在位置的新节点。

y.right = z.right

y.right.p= y

RB-TRANSPLANT(T, z, y)

y.left= z.left

y.left.p= y

y.color= z.color



得出上面的结论后,就看下删除y结点之后,给红黑树的性质带来了哪些变化:

如果y的颜色是RED,则y不可能为红黑树的根,所以不管x的颜色是什么,都不会影响到红黑树的性质。所以只考虑y的颜色为BLACK的情况。



在y的颜色是BLACK的情况下,如果x的颜色为RED的话,删除y之后,结点y所在的分支的黑高就会减1,所以,只需要将x的颜色变为BLACK,则该分支的黑高会加1,则会保持住红黑树的颜色性质。



所以最终要考虑的情况就是,y颜色为BLACK,x的颜色为BLACK的情况。因把y删除后,x顶替y的位置,y所在分支的黑高减1,所以,假设x节点的颜色为BLACK-BLACK,简称BB,也就是原来y的BLACK增加到x上了,这样就保证了该分支的黑高不变,接下来要做的就是调整x所在的分支,使红黑树的性质保持不变,又分为下面的几种情况(只考虑x为左孩子的情况,右孩子的情况是对称的):



对于下面四种情况之间的转换,需要保证转换前和转换后,红黑树的性质都得到了维持。



1:x的兄弟结点w的颜色为RED,记为case1。

因为w为RED,所以x.p的颜色为BLACK,w的两个孩子的颜色都为BLACK,如下图:



转换前,满足下面的性质:

a:bh(p) =bh(x) + 2 = bh(w) = bh(1) + 1 = bh(2) + 1

b:整个分支的黑高为bh(p)+ 1 (p.color == BLACK) = bh(x) + 3



对于这种情况,需要做的调整的代码如下:

w.color =BLACK // case1

x.p.color =RED // case1

LEFT-ROTATE(T,x.p) // case 1

w = x.p.right // case1



经过w.color = BLACK和x.p.color = RED的调整后,如下图:



对结点p进行左旋:LEFT-ROTATE(T, x.p),左旋之后,得到下面的图:



调整后,满足下面的性质:

a:bh(x), bh(1), bh(2)的值保持不变

b:因调整前有:bh(x)+ 2 = bh(1) + 1 = bh(2) + 1

所以,bh(p) = bh(x) + 2 = bh(1) + 1,所以p结点为根的子树满足红黑树性质;


bh(w) = bh(2) + 1 = bh(p),所以w结点为根的子树满足红黑树性质



c:整个分支的黑高为bh(w)+ 1 (w.color == BLACK) = bh(x) + 3,所以,整个分支的黑高没变



这时,x的兄弟的颜色为BLACK,所以经过w = x.p.right后,得到了另外一种情况;



这种情况下,要根据w的孩子结点的颜色不同分为三种情况:



2:首先是w的孩子的颜色都是BLACK的情况下,记为case2:



转换前,满足下面的性质:

a:bh(p) =bh(x) + 2 = bh(1) + 2 = bh(2) + 2 = bh(w)+1



b:整个分支的黑高为bh(p)+ 1/0(p.color == BLACK?1:0) = bh(x) + 3/2(p.color == BLACK?3:2)



对于这种情况,需要调整的代码为:

w.color = RED // case 2

x= x.p //case 2



调整后,得到下面的图:



调整后,满足下面的性质:

a:bh(x), bh(1), bh(2)的值保持不变

b:因调整前有:bh(x)+ 2 = bh(1) + 2 = bh(2) + 2

所以,bh(


)= bh(x) + 1 = bh(1) + 1 = bh(2) + 1,
结点为根的子树满足红黑树性质; bh(w) = bh(1) + 1 = bh(2) + 1, w结点为根的子树满足红黑树性质



如果p,也就是 的颜色为RED,则退出循环,并且置

颜色为BLACK。

c:整个分支的黑高为bh(


)+ 1 (

.color==
BLACK) = bh(x) + 2,所以,整个分支的黑高没变。



如果p的颜色为BLACK,则

的颜色为BLACK-BLACK。

c:整个分支的黑高为bh(


)+ 2 ( .color== BB) = bh(x) + 3,所以,整个分支的黑高没变。



这样, 之下的结点维持了红黑树的性质,然后以 为新的结点继续循环处理。



3:如果w的右孩子结点为RED,左节点颜色为任意,case3:



转换前,满足下面的性质:

a:bh(p) =bh(x) + 2 = bh(2) + 1 = bh(1) + 2/1(1.color == BLACK?2:1)



b:整个分支的黑高为bh(p)+ 1/0(p.color == BLACK?1:0) = bh(x) + 3/2(p.color == BLACK?3:2)


对于这种情况,需要调整的代码为:
w.color = x.p.color // case 3

x.p.color= BLACK //case 3

w.right.color= BLACK //case 3

LEFT-ROTATE(T,x.p) // case3

x = T.root //case 3



经过w.color = x.p.color; x.p.color = BLACK;w.right.color = BLACK之后,得到下面的图:



经过LEFT-ROTATE(T, x.p)和x = T.root之后,得到下图:



调整后,满足下面的性质:

a:bh(x), bh(1), bh(2)的值保持不变

b:因调整前有:bh(x)+ 2 = bh(2) + 1 = bh(1) + 2/1(1.color == BLACK?2:1)

所以,bh(w) = bh(x) + 2 = bh(2) + 1 = bh(1) +2/1(1.color == BLACK?2:1),w结点为根的子树满足红黑树性质; bh(p)
= bh(x) + 1 = bh(1) + 1/0(1.color == BLACK?1:0), w结点为根的子树满足红黑树性质



c:整个分支的黑高为bh(w) + 1/0(p.color == BLACK?1:0)= bh(x) = 3/2(p.color == BLACK?3:2)。所以整个分支的黑高没变。



4:如果w的右孩子结点为BLACK,左节点颜色为RED,case4:



转换前,满足下面的性质:

a:bh(p) =bh(x) + 2 = bh(2) + 2 = bh(1) + 1 = bh(3) + 2 = bh(4) + 2



b:整个分支的黑高为bh(p)+ 1/0(p.color == BLACK?1:0) = bh(x) +3/2(p.color == BLACK?3:2)


对于这种情况,需要调整的代码为:
w.left.color= BLACK // case 4

w.color= RED //case 4

RIGHT-ROTATE(T,w) // case 4

w= x.p.right //case 4


经过w.left.color = BLACK和w.color = RED的调整后,得到下面的图:



经过RIGHT-ROTATE(T.w)和w = x.p.right的调整之后,得到下面的图:



调整后,满足下面的性质:
a:bh(x), bh(3), bh(4), bh(2)的值保持不变

b:因调整前有bh(x)+ 2 = bh(2) + 2 = bh(3) + 2 = bh(4) + 2,所以:

bh(w)= bh(4) + 1 = b(2) + 1,所以,w为根节点的子树红黑树性质没变;
bh(


)= bh(3) + 1 = bh(4) + 1 = b(2) + 1,所以,
为根节点的子树红黑树性质没变;
bh(p)= bh(x) +2 = bh(3) + 2 = bh(4) + 2 = b(2) + 2,所以,p为根节点的子树红黑树性质没变;

c:整个分支的黑高为bh(p)+ 1/0(p.color == BLACK?1:0) = bh(x) +3/2(p.color == BLACK?3:2),所以整个分支的黑高。



同时注意到,新的w(

)颜色为BLACK,而其右孩子为RED,符合case3。


分析:

n个结点的红黑树高度为O(lg n),不调用RB-DELETE-FIXUP时,时间代价为O(lg n),情况1可以转换为情况2;也可以转换为情况3,然后退出循环;也可以转换为情况4,然后情况4可以转换为情况3,情况3只执行一次循环。情况2是唯一能在while循环中执行多次的情况,所以RB-DELETE-FIXUP的时间复杂度为O(lg n)。所以,红黑树的删除的时间复杂度为O(lg n)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: