红黑树删除之向上调整

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, 522个随机数构成的红黑树删除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只嵌套调用了一次

重点

失业了,求职中!能有口饭吃将不胜感激。

相关推荐
LOVE️YOU3 小时前
Python 中 Tuple 为什么有时可 Hash,有时不可 Hash?
开发语言·python·哈希算法
小oo呆3 小时前
【学习心得】迭代器和可迭代对象
开发语言·python
AC赳赳老秦4 小时前
采集行为合规自检:OpenClaw 自动校验 robots 协议与采集频率,规避违规采集风险
java·开发语言·c++·python·php·deepseek·openclaw
迅猛龙办公室4 小时前
Python输出当前计算机的系统日期和时间
开发语言·前端·python
XiaoMaqqqq5 小时前
知名的IP驱动产业新场景新工具
网络·python·网络协议·tcp/ip
言乐65 小时前
Python实现语音审核模型
开发语言·python·django·virtualenv·pygame
程序员清风6 小时前
Python 数据分析环境搭建:从 Jupyter 到 pandas
python·jupyter·数据分析
月光船幽幽6 小时前
加性偏移外推提升参数识别可靠性
python·算法
BD_Marathon7 小时前
消息对象中字段的说明
java·前端·python
Java后端的Ai之路7 小时前
Python进阶探索23 - Python中的Time与Datetime模块
开发语言·数据库·python·datetime·time