红黑树删除之向上调整

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

重点

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

相关推荐
ℳ₯㎕ddzོꦿ࿐1 小时前
解决Python 在 Flask 开发模式下定时任务启动两次的问题
开发语言·python·flask
CodeClimb1 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
一水鉴天1 小时前
为AI聊天工具添加一个知识系统 之63 详细设计 之4:AI操作系统 之2 智能合约
开发语言·人工智能·python
Channing Lewis2 小时前
什么是 Flask 的蓝图(Blueprint)
后端·python·flask
B站计算机毕业设计超人2 小时前
计算机毕业设计hadoop+spark股票基金推荐系统 股票基金预测系统 股票基金可视化系统 股票基金数据分析 股票基金大数据 股票基金爬虫
大数据·hadoop·python·spark·课程设计·数据可视化·推荐算法
觅远2 小时前
python+playwright自动化测试(四):元素操作(键盘鼠标事件)、文件上传
python·自动化
ghostwritten3 小时前
Python FastAPI 实战应用指南
开发语言·python·fastapi
CM莫问3 小时前
python实战(十五)——中文手写体数字图像CNN分类
人工智能·python·深度学习·算法·cnn·图像分类·手写体识别
通信.萌新5 小时前
OpenCV边沿检测(Python版)
人工智能·python·opencv
Bran_Liu5 小时前
【LeetCode 刷题】字符串-字符串匹配(KMP)
python·算法·leetcode