bug
从图来看,向上调整了一层,2的父结点4也做了调整。
删除0
正确的删除
正确删除0后应该是这样的。 [0, 17, 16, 10, 11, 12, 1, 21, 18, 4, 19, 8, 14, 3, 2, 7, 20, 15, 13, 9, 6, 5]22个随机数构成的红黑树删除0。
删除0后 |
---|
错误的删除
调试代码时错误的情况。2作为1的左子树上也不符合二叉查找树的要求。
删除0错误的情况 |
---|
删除之前
删除之前 |
---|
0是黑色结点,删除后会破坏红黑树的平衡。是情形3:兄弟w为黑色,且其孩子左红右空。调整后转成情形4再调整一次就恢复平衡,不用再向上调整。正好是红黑树的删除图例的情形3。
情形四修正
#4.w为黑色,且其孩子左黑右红或左红右红。调试代码是这里出了问题。黑有时也是空的意思。要添加左空右红的情况。
原代码
if w and ((w.left and w.left.color == BLACK and w.right and w.right.color == RED )
改正后
镜像的代码也对应修改。
if w and (((w.left == None or w.left and w.left.color == BLACK )and w.right and w.right.color == RED )
用例
a = [0, 17, 16, 10, 11, 12, 1, 21, 18, 4, 19, 8, 14, 3, 2, 7, 20, 15, 13, 9, 6, 5]
22个数据递增和递减构造的图都是7层,随机数据构造的图是6层。
#22递增的图,递减的图都是7层,随机图6层,
#for v in range(22):
#for v in range(21,-1,-1): #22递增的图
#a = [i for i in range(22)]
#random.shuffle(a)
#print(a)
a = [0, 17, 16, 10, 11, 12, 1, 21, 18, 4, 19, 8, 14, 3, 2, 7, 20, 15, 13, 9, 6, 5]
for v in a:
rb.INSERT(v)
本来想看看删除递归向上调整的情况,一删除0,代码就有问题了。画出图形,用随机数测试还是很有帮助的。
删除1
从前面第一张图"删除0后"可以看出,此时删除1是情形2:兄弟w为黑色,且其孩子为空 。需要向上调整,是怎么调整的呢?
这一删问题更大了,还有好多bug,这里略去了很多图。具体参照红黑树的删除修改。
主要修改
- 1、 反色。要判断之前颜色再设置新颜色。
py
if w.left.color == RED:
w.left.PAINT(BLACK)
else:
w.left.PAINT(RED)
- 2、置 w 与 x . p w与 x. p w与x.p同色。 之前试的例子太少,自以为是地写成了黑色。
- 3、黑有时是表示NIL结点。
修改前
py
#2.w为黑色或空,且其孩子左黑右黑
if w == None or (w.left and w.left.color == BLACK and w.right and w.right.color == BLACK)or(w.left is None and w.right is None):
if w:w.PAINT(RED)
if p.parent:
p.PAINT(BLACK)
if p == p.left:
w = p.right
p = p.parent
else:
w = p.right
p = p.parent
self.DELETE_FIXUP(p,w)
#4.w为黑色,且其孩子左黑右红或左红右红
if w and (((w.left == None or w.left and w.left.color == BLACK ) and w.right and w.right.color == RED )
or (w.left and w.left.color == RED and w.right and w.right.color == RED)):
p.PAINT(BLACK)
if w == p.right:
self.LEFT_ROTATE(p)
w.right.PAINT(BLACK)
elif w == p.left:
self.RIGHT_ROTATE(p)
w.left.PAINT(BLACK)
#镜像情况
elif w and (((w.right == None or w.right and w.right.color == BLACK ) and w.left and w.left.color == RED )
or (w.right and w.right.color == RED and w.left and w.left.color == RED)):
p.PAINT(BLACK)
if w == p.left:
self.RIGHT_ROTATE(p)
w.left.PAINT(BLACK)
elif w == p.right:
self.LEFT_ROTATE(p)
w.right.PAINT(BLACK)
修改后
py
#2.w为黑色或空,且其孩子左黑右黑
if w == None or (w.left and w.left.color == BLACK and w.right and w.right.color == BLACK)or(w.left is None and w.right is None):
if w:w.PAINT(RED)
if p.parent:
if p == p.parent.left:
w = p.parent.right
p = p.parent
else:
w = p.parent.right
p = p.parent
self.DELETE_FIXUP(p,w)
#3.w为黑色,且其孩子左红右黑
if w and w.left and w.left.color == RED and (w.right == None or w.right and w.right.color == BLACK):
w.left.PAINT(BLACK)
w.PAINT(RED)
self.RIGHT_ROTATE(w)
w = p.right
#镜像情况
elif w and w.right and w.right.color == RED and (w.left == None or w.left and w.left.color == BLACK):
w.right.PAINT(BLACK)
w.PAINT(RED)
self.LEFT_ROTATE(w)
w = p.left
#4.w为黑色,且其孩子左黑右红或左红右红
if w and (((w.left == None or w.left and w.left.color == BLACK ) and w.right and w.right.color == RED )
or (w.left and w.left.color == RED and w.right and w.right.color == RED)):
w.PAINT(p.color)
p.PAINT(BLACK)
if w == p.right:
self.LEFT_ROTATE(p)
if w.right.color == RED:
w.right.PAINT(BLACK)
else:
w.right.PAINT(RED)
elif w == p.left:
self.RIGHT_ROTATE(p)
if w.left.color == RED:
w.left.PAINT(BLACK)
else:
w.left.PAINT(RED)
#镜像情况
elif w and (((w.right == None or w.right and w.right.color == BLACK ) and w.left and w.left.color == RED )
or (w.right and w.right.color == RED and w.left and w.left.color == RED)):
w.PAINT(p.color)
p.PAINT(BLACK)
if w == p.left:
self.RIGHT_ROTATE(p)
if w.left.color == RED:
w.left.PAINT(BLACK)
else:
w.left.PAINT(RED)
elif w == p.right:
self.LEFT_ROTATE(p)
if w.right.color == RED:
w.right.PAINT(BLACK)
else:
w.right.PAINT(RED)
还是错
删除调整修正后删除1的图 |
---|
3在2的左支,不符合红黑树,也不符合二叉排序树。
调试
不应该啊,已接近崩溃,又做了如下测试。
rb.DELETE(1)
rb.draw(rb.root)
rb.root.left.left.left.left.val
Traceback (most recent call last):
File "<pyshell#47>", line 1, in <module>
rb.root.left.left.left.left.val
AttributeError: 'NoneType' object has no attribute 'val'
rb.root.left.left.left.right.val
3
2的左支没有3,它在右支。不会是画图代码有问题吧!加个search方法直接定位结点,这就是后话了。
修正
之前编码时,先写的只有左支的情况,是入队左和NIL。再抄到只有右支的情况,写成了先入队右再入队NIL。
py
elif q.right:
temp.append(RBTnode(-1))
temp.append(q.right)
endlevel = level + 1
#之前写的是:
elif q.right:
temp.append(q.right)
temp.append(RBTnode(-1))
endlevel = level + 1
代码里还有错吗? |
---|
从图来看,向上调整了一层,2的父结点4也做了调整。也许一直向上调整的情况没有那么容易碰到。调试情况如下:
DELETE_FIXUP只嵌套调用了一次 |
---|
重点
失业了,求职中!能有口饭吃将不胜感激。