红黑树删除之向上调整

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只嵌套调用了一次

重点

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

相关推荐
李晨卓5 小时前
python学习之不同储存方式的操作方法
python·代码规范
站大爷IP5 小时前
实战:爬取某联招聘职位需求并生成词云——从零开始的完整指南
python
deephub5 小时前
从零开始:用Python和Gemini 3四步搭建你自己的AI Agent
人工智能·python·大语言模型·agent
咕白m6255 小时前
Python 实现 PDF 页面旋转
python
c***87196 小时前
Flask:后端框架使用
后端·python·flask
Q_Q5110082857 小时前
python+django/flask的情绪宣泄系统
spring boot·python·pycharm·django·flask·node.js·php
撸码猿7 小时前
《Python AI入门》第9章 让机器读懂文字——NLP基础与情感分析实战
人工智能·python·自然语言处理
二川bro7 小时前
多模态AI开发:Python实现跨模态学习
人工智能·python·学习
2301_764441337 小时前
Python构建输入法应用
开发语言·python·算法
love530love7 小时前
【笔记】ComfUI RIFEInterpolation 节点缺失问题(cupy CUDA 安装)解决方案
人工智能·windows·笔记·python·插件·comfyui