红黑树删除

14 篇文章 0 订阅

简介

https://blog.csdn.net/weixin_43868793/article/details/123114745

删除

红黑树结点的删除可以分为两步

  1. 找到最终决定要移除的结点
  2. 通过红黑树的基本操作(左旋,右旋,变色)来保持红黑树性质

一、找到最终决定要移除的结点

先通过find方法找到目标结点,大概有两种情况

1 无子

例如整个树只有一个根结点:12最终决定要移除的结点即为12

12
null
null

2 有子

7
10
11
12
14
15

只需向下寻找替代结点,用替代结点的值覆盖欲删除的结点,然后这个替代结点成为新的欲删除的结点,继续判断。

2.1 删除有独子的结点

例如上图,删除14,可以找到替代结点15,15覆盖14,而15红结点无子得

7
10
11
12
15
15 最终决定要删除的结点
2.2 删除有多子的结点

例如上图,删除10黑结点,那么需要在左子树中找到最大结点右子树中找到最小结点,然后从中得到一个比较小的那个结点,作为替代结点
为什么要怎么做呢?
红黑树有保序的,对上图这个树从根开始对树做中序遍历,会得到序列7,10,11,12,14,15,是有序的,
如果不那样做,不能做到保序。

7
11
12
14
15
7 替代删除结点

二、恢复红黑树性质

找到了最终决定要移除的结点后,这个结点必定是一个叶子结点,直接删除可能会影响红黑树性质,需要根据一系列情况,做一些操作来恢复其性质。

大体分两种情况

1 红

最终决定要移除的结点删除后不会影响红黑树的性质!

2 黑

2.1 红色兄弟

如图

43
50
57
60
64
67
nil

现在欲删除43
左边删除掉43黑之后,左子树黑高 -1,显然以父为支,作左旋可以弥补缺失的黑高!,得到

50
57
60
64
67
nil
nil

可以发现,左边黑高多出一个,而且60是根的时候,不应该是红色的,所以必需观察兄弟结点的左子的情况!再决定。

2.1.1 红色的兄弟有左子

根据红黑树性质,红色结点的父必是黑色,红色结点的子必是黑色!,
所以可以做一次双旋!,以兄弟为支,作右旋,再以父为支,作左旋得到

50
57
60
64
67
nil

恢复红黑树性质

2.1.2 红色的兄弟无左子

在删除的过程会出现,但红黑树本身并不会出现这种情况

2.2 黑色兄弟

一个结点是黑色的,其父可黑可红,其两个子结点可黑可红
但调整红黑树,只城要考虑父结点,和靠近自己的一个侄子即可
即有

  • 黑色兄弟,黑父,黑侄
  • 黑色兄弟,红父,红侄
  • 黑色兄弟,红父,黑侄
  • 黑色兄弟,黑父,红侄
2.2.1 黑色兄弟,黑父,黑侄

不会出现这种情况,不满足红黑树性质

2.2.2 黑色兄弟,红父,红侄

如图

43
50
57
60
63
64
67

现在欲删除结点57,显然双旋操作可以实现恢复红黑树性质
对其父60红左双旋

43
50
60
63
64
67

再将60变色得

43
50
60
63
64
67

但如果考虑下面这种没有左侄情况,直接以父为支左旋即可
欲删除结点57

40
43
45
50
57
60
64
67
nil
2.2.3 黑色兄弟,红父,黑侄
2.2.4 黑色兄弟,黑父,红侄

如下图欲删除结点25

25
50
60
75
80

以50为支作左双旋得

50
60
75
80

然后60红变色得

50
60
75
80

如果是下面这种没有左侄的情况,

25
50
75
80
nil

父变色,以父为支直接左旋即可得

50
75
80

三、重新总结下如何恢复红黑树性质

约定:
欲删除结点为目标结点

直接删除

目标结点是红色的情况,直接删除即可

父置红,以父为支作单旋

目标结点是黑色,目标结点是左子,兄弟结点没有左子
目标结点是黑色,目标结点是右子,兄弟结点没有右子

侄置黑,以父为支作双旋

目标结点是黑色,目标结点是左子,兄弟结点有左子
目标结点是黑色,目标结点是右子,兄弟结点有右子

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
红黑树删除操作相对比较复杂,需要考虑多种情况。下面是一个简单的红黑树删除的 Java 实现示例: ```java public class RedBlackTree { private Node root; // 其他代码... public void delete(int value) { Node node = search(root, value); if (node != null) { deleteNode(node); } } private void deleteNode(Node node) { Node y = node; Node x; boolean yOriginalColor = y.isBlack(); if (node.getLeft() == null) { x = node.getRight(); transplant(node, node.getRight()); } else if (node.getRight() == null) { x = node.getLeft(); transplant(node, node.getLeft()); } else { y = minimum(node.getRight()); yOriginalColor = y.isBlack(); x = y.getRight(); if (y.getParent() == node) { if (x != null) { x.setParent(y); } } else { transplant(y, y.getRight()); y.setRight(node.getRight()); y.getRight().setParent(y); } transplant(node, y); y.setLeft(node.getLeft()); y.getLeft().setParent(y); y.setColor(node.getColor()); } if (yOriginalColor) { deleteFixup(x); } } private void deleteFixup(Node x) { while (x != root && x.isBlack()) { if (x == x.getParent().getLeft()) { Node w = x.getParent().getRight(); if (!w.isBlack()) { w.setBlack(true); x.getParent().setBlack(false); leftRotate(x.getParent()); w = x.getParent().getRight(); } if (w.getLeft().isBlack() && w.getRight().isBlack()) { w.setBlack(false); x = x.getParent(); } else { if (w.getRight().isBlack()) { w.getLeft().setBlack(true); w.setBlack(false); rightRotate(w); w = x.getParent().getRight(); } w.setBlack(x.getParent().isBlack()); x.getParent().setBlack(true); w.getRight().setBlack(true); leftRotate(x.getParent()); x = root; } } else { Node w = x.getParent().getLeft(); if (!w.isBlack()) { w.setBlack(true); x.getParent().setBlack(false); rightRotate(x.getParent()); w = x.getParent().getLeft(); } if (w.getRight().isBlack() && w.getLeft().isBlack()) { w.setBlack(false); x = x.getParent(); } else { if (w.getLeft().isBlack()) { w.getRight().setBlack(true); w.setBlack(false); leftRotate(w); w = x.getParent().getLeft(); } w.setBlack(x.getParent().isBlack()); x.getParent().setBlack(true); w.getLeft().setBlack(true); rightRotate(x.getParent()); x = root; } } } x.setBlack(true); } // 其他辅助方法... } ``` 这只是一个简单的实现示例,更详细和完善的红黑树删除算法可以参考相关的算法书籍或网络资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tadus_zeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值