红黑树的删除

导航链接

    红黑树的性质
    红黑树的旋转、变色
    红黑树的插入
    红黑树的删除

文章目录

    • 导航链接
    • 二叉搜索树如何删除结点?
      • 场景一:删除没有孩子的结点
      • 场景二:删除有一个孩子的结点
      • 场景三:删除有两个孩子的结点
    • 红黑树如何删除结点?
      • 场景一:被删结点无孩子,且被删结点为红色
      • 场景二:被删结点无孩子,且被删结点为黑色
      • 场景三:被删结点有一个孩子(被删结点一定是红色,子结点为黑色)
      • 场景四:被删结点有两个孩子
      • 怎样删除无孩子的黑结点?
        • 结构1:兄为黑,且有一个子结点为红,与兄结点同一斜边上
        • 结构2:兄为黑,且有一个子结点为红,与兄结点不在同一斜边上
        • 结构3:兄为黑,且没有红色的子结点,父为
        • 结构4:兄为黑,且没有红色的子结点,父为
        • 结构5:兄为红,父为黑
    • 总结


友情提醒,接下来你可能会很困,因为红黑树删除结点真麻烦。。。

二叉搜索树如何删除结点?

我们先看看,二叉搜索树是怎样删除结点,从中我们又能获得怎样的启发。二叉搜索树的删除操作比较简单,可以分为以下三种场景。

场景一:删除没有孩子的结点

删除没有孩子的结点,对排序并不会产生任何影响,所以可直接删除(呃,么有孩子的结点,也就么得牵挂)。

在这里插入图片描述


场景二:删除有一个孩子的结点

删除有一个孩子的结节,则可以让孩子结点顶替当前结点(子承父业),继续保持原有排序。

在这里插入图片描述


场景三:删除有两个孩子的结点

删除有两个孩子的结点,那就必须从后代中找到一个离它最近的子孙,替换当前结点的值,再删除子孙结点。(子孙替我挡刀)
在这里插入图片描述

至于选取哪个最近的结点,无特殊规定。比如在Min<...<Y<X<Z<...<Max排序中你删除X,你即可以选择Y代替,也可以选择Z代替。二叉搜索树中,称Y为后继,Z为前驱。





红黑树如何删除结点?

但红黑树的删除没有那么简单,因为上述的删除操作,都可能破坏红黑树的性质。

如果按场景一方式删除结点800,会导致200->400->600->leaf这条路径比200->400->600->500->550->leaf少一个根结点,从而违背了 《从任意结点到其每个叶子的所有路径都包含相同数目的黑色结点》

在这里插入图片描述

按场景二的方式删除下图的中800结点,使用其唯一的孩子结点900代替,会导致600900成为两个连续的红结点。从而违背了 《从每个叶子到根的所有路径上不能有两个连续的红结点》

在这里插入图片描述

按场景三的方式删除下图的中400结点,用最近的结点325的拷贝到当前位置,再将325移除,会导致300310成为两个连续的红结点。也违背了 《从每个叶子到根的所有路径上不能有两个连续的红结点》

在这里插入图片描述

上面只是列举了部分例子,有些时候可能违背的性质会更多。但二叉搜索树的删除方式并不是毫无借鉴可言,我们可以在它的操作上,再添加一些维护红黑树性质的动作。也就是说,红黑树删除结点 = 二叉搜索树删除结点 + 旋转、变色


红黑树的删除主要有以下四种场景。

场景一:被删结点无孩子,且被删结点为红色

因为无孩子的红色结点一定会在树的最下层,删除之后也不会影响树的高度,所以可以直接删除。

在这里插入图片描述


场景二:被删结点无孩子,且被删结点为黑色

如果一个黑色结点没有孩子,直接删除会使一条支路上黑色结点数量减一,需要适当调整树的结构,后面再说。

在这里插入图片描述


场景三:被删结点有一个孩子(被删结点一定是红色,子结点为黑色)

首先,只有一个孩子的结点,不可能是黑色,因为这样会导致从该结点出发,到叶子结点的路径高度不一致。

在这里插入图片描述

所以这样的结点只能是红色,并且根据 《从每个叶子到根的所有路径上不能有两个连续的红结点》 可以推断,其子结点一定是黑色。

删除这样的结点也很简单,只需要让子结点覆盖当前结点,同样变成黑色即可。这样只是少了一个红节点,不会破坏树的结构。

在这里插入图片描述


场景四:被删结点有两个孩子

当删除有两个孩子的结点时,和二叉搜索树删除一样,也是先找到后继结点,替换当前结点的值,进而转变成删除后继结点。值得注意的是,只需要替换值,不需要替换颜色。如图,删除310结点。

在这里插入图片描述

而无论删除哪个后继结点,又会回到之前的三种场景,比如说:

删除上图中的50结点,它有两个孩子,后继结点为25。删除它又等于回到了场景三,被删结点有一个孩子。

删除上图中的320结点,它有两个孩子,后继结点为315。删除它又等于回到了场景二,被删结点无孩子,结点为黑色。

删除上图中的325结点,它有两个孩子,后继结点为324。删除它又等于回到了场景一,被删结点无孩子,结点为红色。如图:

在这里插入图片描述

所以重点还是回到了怎样删除无孩子的黑结点。


怎样删除无孩子的黑结点?

通过场景二的图片不难看出,删除一个没有子结点的黑结点,势必会造成二叉树的一条支路变短。如果想平衡树高,就必须结合待删除结点的父(Parent)、兄(Brother)、侄子(或叫外甥,Nephew)结点综合考虑,如何通过旋转、变色,恢复红黑树的特性。

结构1:兄为黑,且有一个子结点为红,与兄结点同一斜边上

兄结点为黑色,兄结点有一个子结点为红色,并且兄结点与该结点在同一条斜边上。这时我们不需要关心父结点的颜色,可红可黑,所以将它染成从红到黑的渐变色。

在这里插入图片描述

上图中的123分别代表其它子树,D结点就是待删除结点。D结点被删除后,会用一个双黑结点NIL代替它(一个空结点,但它权值为2,代表着两个黑结点)。接下来就是平衡的过程,把这个多出来的黑色权值扔掉,使它成为一个普通的黑结点,最终整个删除操作完成。

对于这样的结构,需要进行如下转换:

  1. 将父结点右旋(待删除结点为右结点,如果为左结点,则改为左旋)。
  2. 父结点与兄结点互换颜色,并且将侄结点变成黑色。
  3. 将双黑结点变成普通的叶结点。

如图:

在这里插入图片描述

完整动画展示如下:

在这里插入图片描述


结构2:兄为黑,且有一个子结点为红,与兄结点不在同一斜边上

兄结点为黑色,兄结点有一个子结点为红色,并且兄结点与该结点不在同一条斜边上。这时候我们也无需关注父结点的颜色,只需要将其转换成结构1,具体操作如下:

  1. 将兄点左旋(侄结点为右孩子,如果为左孩子,则改为右旋)。
  2. 兄结点与侄结点互换颜色。

如图:

在这里插入图片描述

完整动画展示如下:

在这里插入图片描述


结构3:兄为黑,且没有红色的子结点,父为

兄结点为黑色,并且没有红色的子结点,并且父结点为红色。

这样结构处理相对简单:

  1. 将兄结点变成红色。
  2. 将父结点变成黑色。
  3. 将双黑结点变成普通叶结点。

在这里插入图片描述

因为兄结点没有红色子结点,所以它是可以变成红色的。这样左右两边高度同时减一,再让父结点由红变黑,高度又和原来一样了。

示例:

在这里插入图片描述

删除结点400,先将后继节点300的值填入到400结点,进行删除300结点。接下来,用双黑结点代替300,组成结构3。直接将兄弟结点变红,父结点变黑,就完成了删除。


结构4:兄为黑,且没有红色的子结点,父为

兄结点为黑色,并且没有红色的子结点,并且父结点为黑色。

面对这样的结构,无论怎样变化,兄结点那一侧永远都会多一个黑结点,所以只能将兄结点变成红色,让父结点变成双黑结点。这样,就让父结点成为了待删除的结点,让父结点继续再与它的兄结点、父结点去判断,调整。

在这里插入图片描述

示例:

在这里插入图片描述

删除结点10时,父、兄结点都为黑色,没有红色的侄结点。进行的操作就是,用双黑结点替换待10,再让兄结点35变成红色,父结点25成为双黑结点。再继续对25进行删除操作,进行其它场景判断。


结构5:兄为红,父为黑

兄结点为红色,那么它的父结点一定为黑色,因为 《从每个叶子到根的所有路径上不能有两个连续的红结点》。并且,它的孩子,不管有没有,都会是黑色。

这样的结构,删除操作也能一步到位,具体如下:

  1. 父结点右旋转(待删除为右孩子,如果为左孩子,则为左旋)。
  2. 将父结点与兄结点交换颜色。
  3. 将双黑结点变成普通叶结点。

在这里插入图片描述

这样,由于旋转导致待删除结点那一侧增加了一个黑结点,所以能就去掉双黑结点的权值,使其变成普通结点啦。

示例:

在这里插入图片描述

待删除结点100的兄结点25是红色,且父结点50是黑色,所以删除时,让50进行了右旋,并且互换了5025的颜色。


总结

好了,到这红黑树的删除总算讲完了,不知道你有没有睡着。重点是,红黑树的删除 = 删除 + 维护,无论怎样删除结点,都会动态的调整树高。 如果有发现不对的地方,烦请留言,我会第一时间纠正,谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/280446.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

海康visionmaster-分支字符:控制调试模式开关的方

在图的右边分支字符模块有两个分支&#xff0c;通过 C#代码 GetParamValue 函数可以看到调试模 式的相关参数 ModuleInfoList 的值为&#xff1a;4#1#0KaTeX parse error: Expected EOF, got # at position 3: 10#̲0#0。其中分支 4#1#0$的 4 表示模 块 id&#xff0c;1 表示这…

操作系统:可变分区管理

有作业序列&#xff1a;作业A要求42K&#xff1b;作业B要求27K&#xff0c;作业C要求22K&#xff0c;作业和空闲内存区如下图所示&#xff0c;请画出最佳适应算法空闲队列图&#xff0c;并分析最佳适应算法是否适合该作业系列。 答&#xff1a;最佳适应算法是按照空闲块由小到大…

Harmony全局应用生命周期 EntryAbility.ts 讲解

之前 我们说过 page页面的生命周期 组件的生命周期 其实他和uni一样有一个整个应用的生命周期 我们如下图打开EntryAbility.ts 这是我们整个程序app的状态控制 他这里也有几个全局的生命周期 比如 我们手机 点开当前 App 启动 app 会触发 它的 onCreate 生命周期 当我们从手…

前端 js 基础(2)

js For In for in 循环遍历 person 对象每次迭代返回一个键 (x)键用于访问键的值键的值为 person[x] 如果索引顺序很重要&#xff0c;请不要在数组上使用 for in。 索引顺序依赖于实现&#xff0c;可能不会按照您期望的顺序访问数组值。 当顺序很重要时&#xff0c;最好使用 f…

元旦特辑:Note6---选择排序

目录 前言❌ 1. 基本思想⚠️ 2. 直接选择排序&#x1f7e2; 2.1 思路分析✳️ 2.2 代码实现❎ 2.2.1 sort.h 2.2.2 sort.c 2.2.3 test.c 2.3 问题解决❇️ 2.3.1 sort.c修改 2.4 特性总结✅ 3. 堆排序&#x1f535; 3.1 代码实现&#x1f3e7; 3.2 特性总结&…

Centos安装Kafka(KRaft模式)

1. KRaft引入 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。其核心组件包含Producer、Broker、Consumer&#xff0c;以及依赖的Zookeeper集群。其中Zookeeper集群是Kafka用来负责集群元数据的管理、控制器的选举等。 由…

c++ 简单实用万能异常捕获

多层捕获异常&#xff0c;逐渐严格。并打印出错信息和位置&#xff1a;哪个文件&#xff0c;哪个函数&#xff0c;具体哪一行代码。 #include <stdexcept> // 包含标准异常类的头文件try {int a 2 / 0; }catch (const std::runtime_error& e) {// 捕获 std::runt…

浅谈 JSON 对象和 FormData 相互转换,打通前端与后端的通信血脉

前言 大家都知道&#xff0c;前端在和后台进行交互联调时&#xff0c;肯定避免不了要传递参数&#xff0c;一般情况下&#xff0c;params 在 get 请求中使用&#xff0c;而 post 请求下&#xff0c;我们有两种常见的传参方式&#xff1a; JSON 对象格式和 formData 格式&#x…

AtCoder Beginner Contest 334 G

G.Christmas Color Grid 2&#xff08;枚举&#xff0c;Tarjan&#xff09; 题意&#xff1a; 本题与问题 E E E类似。有一个 H H H行和 W W W列的网格&#xff0c;每个单元格都被涂成红色或绿色。用 ( i , j ) (i,j) (i,j)表示从上到下第 i i i行、从左到右第 j j j列的单元…

UIToolKit使用心得

起因 因为那个uitoolkit自己写了一套graphView&#xff0c;所以想着来用用但是用完之后发现也不过如此 怎么构建自己的组件 我在继承Node之后想修改node的样式该怎么办呢是这样的。先用pick点击默认的node节点元素- 在pick默认创建的node节点之后&#xff0c;可以把它的uxml…

跨境电商迎来综合竞争力比拼时代 五大趋势解读跨境2024

过去几年&#xff0c;跨境电商成为外贸出口增长的一大亮点&#xff0c;随着年底国务院办公厅《关于加快内外贸一体化发展的若干措施》的发布&#xff0c;跨境电商在促进经济发展、助力内外贸一体化发展方面的价值更加凸显。 这是跨境电商变化最快的时代&#xff0c;也是跨境电…

CCSK认证:开启云安全领域的黄金大门

&#x1f31f;你是否对云安全领域充满热情&#xff1f;是否希望提升自己在云安全领域的专业性和竞争力&#xff1f;CCSK认证是你的不二之选&#xff01; &#x1f525;CCSK简介&#xff1a; CCSK是国际云安全联盟&#xff08;Cloud Security Alliance&#xff0c;CSA&#xff…

Vue3-29-路由-编程式导航的基本使用

补充一个知识点 路由配置中的 name 属性 &#xff1a; 可以给你的 路由 指定 name属性&#xff0c;称之为 命名路由。 这个 name 属性 在 编程式导航 传参时有重要的作用。 命名路由的写法如下 &#xff1a; 像指定 path 一样&#xff0c;直接指定一个 name 属性即可。{path:/d…

【已解决】 ubuntu apt-get update连不上dl.google.com

在终端使用apt-get update时&#xff0c;连接dl.google.com超时&#xff0c;一直卡在0%&#xff0c;原因是当前ip无法ping到google&#xff08;墙&#xff09;。 解决方法&#xff1a; dl.google.com国内可用IP 选一个&#xff0c;然后按以下命令操作&#xff1a; cd ~ vim …

RSA加密解密——用shell加密java解密

功能描述 使用shell opensll对明文进行RSA加密&#xff0c;将密文用java的RSA工具对密文解密。这应该是全网第一个同时用到shell和java的RSA加密解密教程。中间有很多坑&#xff0c;都踩过了&#xff0c;可以放心使用代码。 正确的实现流程 shell端 首先生成公钥私钥 &…

飞企互联-FE企业运营管理平台 登录绕过漏洞复现

0x01 产品简介 飞企互联-FE企业运营管理平台是一个基于云计算、智能化、大数据、物联网、移动互联网等技术支撑的云工作台。这个平台可以连接人、链接端、联通内外&#xff0c;支持企业B2B、C2B与O2O等核心需求&#xff0c;为不同行业客户的互联网转型提供支持。 0x02 漏洞概…

大数据Doris(四十五):物化视图选择最优

文章目录 物化视图选择最优 物化视图选择最优 下面详细解释一下第一步最优物化视图是被如何选择出来的。 这里分为两个步骤: 对候选集合进行一个过滤。只要是查询的结果能从物化视图数据计算(取部分行,部分列,或部分行列的聚合)出都可以留在候选集中,过滤完成后候选集合…

图像中的傅里叶变换及低通与高通滤波

傅里叶变换 高频&#xff1a;在图像中变化剧烈的灰度分量&#xff0c;如边界。 低频&#xff1a;在图像中变化缓慢的灰度分量。 OpenCV中函数为cv2.dft()和cv2.idft()&#xff0c;输入图像要先转换成np.float32格式。得到的结果频率为0的部分会在左上角&#xff0c;为方便处理…

【yolofastest上手】

一、前言 yolofastest网上资料比较少&#xff0c;也没有视频教学&#xff0c;所以想要使用参考了很多资料&#xff0c;只能说各资料都不尽全&#xff0c;让刚接触的小白无从下手。 参考资料: github地址 yolo-fastest 快速上手 修改参数遇到的问题 能在ARM-CPU上实时识别图像的…

MES系统中的电子看板:真正实现数字化车间可视化

在生产制造过程中&#xff0c;看板管理扮演着至关重要的角色。通过看板&#xff0c;我们能够实时了解生产情况、物料需求、质量预警等信息&#xff0c;从而更好地控制生产过程。作为万界星空科技MES管理系统中的一个基本模块&#xff0c;看板管理为企业的生产管理提供了有力支持…