漫画:什么是红黑树?(整合版)

前段时间,小灰发布了红黑树相关的文章,分成上下篇来讲解。

这一次,小灰把两篇文章做了整合,并且修正了红黑树删除部分的图片错误,感谢大家的指正。

—————  第二天  —————

————————————

二叉查找树(BST)具备什么特性呢?

1.子树上所有结点的值均小于或等于它的根结点的值。

2.子树上所有结点的值均大于或等于它的根结点的值。

3.左、右子树也分别为二叉排序树。

下图中这棵树,就是一颗典型的二叉查找树:

1.查看根结点9

2.根据二叉查找树左子树小、右子树大的特性,10 > 9,因此值为10的结点只可能在根结点的右子树当中,我们查看右孩子结点13

3.由于10 < 13,因此查看左孩子11

4.由于10 < 11,因此查看左孩子10,发现10正是要查找的结点:


假设初始的二叉查找树只有三个结点,根结点值为9,左孩子值为8,右孩子值为12:

接下来我们依次插入如下五个结点:7,6,5,4,3。依照二叉查找树的特性,结果会变成什么样呢?

1.结点是红色或黑色。

2.根结点是黑色。

3.每个叶子结点都是黑色的空结点(NIL结点)。

4 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)

5.从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。

下图中这棵树,就是一颗典型的红黑树:

什么情况下会破坏红黑树的规则,什么情况下不会破坏规则呢?我们举两个简单的例子:

1.向原红黑树插入值为14的新结点:

由于父结点15是黑色结点,因此这种情况并不会破坏红黑树的规则,无需做任何调整。

2.向原红黑树插入值为21的新结点:

由于父结点22是红色结点,因此这种情况打破了红黑树的规则4(每个红色结点的两个子结点都是黑色),必须进行调整,使之重新符合红黑树的规则。

变色:

为了重新符合红黑树的规则,尝试把红色结点变为黑色,或者把黑色结点变为红色。

下图所表示的是红黑树的一部分(子树),新插入的结点Y是红色结点,它的父亲结点X也是红色的,不符合规则4,因此我们可以把结点X从红色变成黑色:

但是,仅仅把一个结点变色,会导致相关路径凭空多出一个黑色结点,这样就打破了规则5。因此,我们需要对其他结点做进一步的调整,后文会详细说明。

左旋转:

逆时针旋转红黑树的两个结点,使得父结点被自己的右孩子取代,而自己成为自己的左孩子。说起来很怪异,大家看下图:

图中,身为右孩子的Y取代了X的位置,而X变成了自己的左孩子。此为左旋转。

右旋转:

顺时针旋转红黑树的两个结点,使得父结点被自己的左孩子取代,而自己成为自己的右孩子。大家看下图:

图中,身为左孩子的Y取代了X的位置,而X变成了自己的右孩子。此为右旋转。

局面1:新结点(A)位于树根,没有父结点。

(空心三角形代表结点下面的子树)

这种局面,直接让新结点变色为黑色,规则2得到满足。同时,黑色的根结点使得每条路径上的黑色结点数目都增加了1,所以并没有打破规则5。

局面2:新结点(B)的父结点是黑色。

这种局面,新插入的红色结点B并没有打破红黑树的规则,所以不需要做任何调整。

局面3:新结点(D)的父结点和叔叔结点都是红色。

这种局面,两个红色结点B和D连续,违反了规则4。因此我们先让结点B变为黑色:

这样一来,结点B所在路径凭空多了一个黑色结点,打破了规则5。因此我们让结点A变为红色:

这时候,结点A和C又成为了连续的红色结点,我们再让结点C变为黑色:

经过上面的调整,这一局部重新符合了红黑树的规则。

局面4:新结点(D)的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的右孩子,父结点(B)是祖父结点的左孩子。

我们以结点B为轴,做一次左旋转,使得新结点D成为父结点,原来的父结点B成为D的左孩子:

这样一来,进入了局面5。

局面5:新结点(D)的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的左孩子,父结点(B)是祖父结点的左孩子。

我们以结点A为轴,做一次右旋转,使得结点B成为祖父结点,结点A成为结点B的右孩子:

接下来,我们让结点B变为黑色,结点A变为红色:

经过上面的调整,这一局部重新符合了红黑树的规则。

以上就是红黑树插入操作所涉及的5种局面。

或许有人会问,如果局面4和局面5当中的父结点B是祖父结点A的右孩子该怎么办呢?

很简单,如果局面4中的父结点B是右孩子,则成为了局面5的镜像,原本的右旋操作改为左旋;如果局面5中的父结点B是右孩子,则成为了局面4的镜像,原本的左旋操作改为右旋。

给定下面这颗红黑树,新插入的结点是21:

显然,新结点21和它的父结点22是连续的红色结点,违背了规则4,我们应该如何调整呢?

让我们回顾一下刚才讲的5种局面,当前的情况符合局面3:

“新结点的父结点和叔叔结点都是红色。”

于是我们经过三次变色,22变为黑色,25变为红色,27变为黑色:

经过上面的调整,以结点25为根的子树符合了红黑树规则,但结点25和结点17成为了连续的红色结点,违背规则4。

于是,我们把结点25看做一个新结点,正好符合局面5的镜像:

“新结点的父结点是红色,叔叔结点是黑色或者没有叔叔,且新结点是父结点的右孩子,父结点是祖父结点的右孩子”

于是我们以根结点13为轴进行左旋转,使得结点17成为了新的根结点:

接下来,让结点17变为黑色,结点13变为红色:

如此一来,我们的红黑树变得重新符合规则。

二叉查找树是如何进行删除操作的呢?可以分成三种情况。

情况1,待删除的结点没有子结点:

上图中,待删除的结点12是叶子结点,没有孩子,因此直接删除即可:

情况2,待删除的结点有一个孩子:

上图中,待删除的结点13只有左孩子,于是我们让左孩子结点11取代被删除的结点,结点11以下的结点关系无需变动:

情况3,待删除的结点有两个孩子:

上图中,待删除的结点5有两个孩子,这种情况比较复杂。此时,我们需要选择与待删除结点最接近的结点来取代它。

上面的例子中,结点3仅小于结点5,结点6仅大于结点5,两者都是合适的选择。但习惯上我们选择仅大于待删除结点的结点,也就是结点6来取代它。

于是我们复制结点6到原来结点5的位置:

被选中的结点6,仅大于结点5,因此一定没有左孩子。所以我们按照情况1或情况2的方式,删除多余的结点6:

红黑树的特性(规则)如下:

1.结点是红色或黑色。

2.根结点是黑色。

3.每个叶子结点都是黑色的空结点(NIL结点)。

4.每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)

5.从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。

下面我们通过一个例子,来看一看删除红黑树的结点会对规则产生怎样的影响:

上图的这颗红黑树,待删除的是黑色结点1,有一个右孩子。根据二叉查找树的删除流程,我们让右孩子结点6直接取代结点1:

显然,这颗新的二叉树打破了两个规则:

规则4. 每个红色结点的两个子结点都是黑色。

规则5. 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。

第一步:如果待删除结点有两个非空的孩子结点,转化成待删除结点只有一个孩子(或没有孩子)的情况。

上面例子是一颗红黑树的局部,标数字的三角形代表任意形态的子树,假设结点8是待删除结点。

根据上文讲解的二叉查找树删除流程,由于结点8有两个孩子,我们选择仅大于8的结点10复制到8的位置,结点颜色变成待删除结点的颜色:

接下来我们需要删除红色的结点10:

红色结点10能成为仅大于8的结点,必定没有左孩子结点,所以问题转换成了待删除结点只有一个右孩子(或没有孩子)的情况。接下来我们进入第二步。

第二步:根据待删除结点和其唯一子结点的颜色,分情况处理。

情况1,自身是红色,子结点是黑色:

这种情况最简单,按照二叉查找树的删除操作,删除结点1即可:

情况2,自身是黑色,子结点是红色:

这种情况也很简单,首先按照二叉查找树的删除操作,删除结点1:

此时,这条路径凭空减少了一个黑色结点,那么我们把结点2变成黑色即可:

情况3,自身是黑色,子结点也是黑色,或者子结点是空叶子结点:

这种情况最复杂,涉及到很多变化。首先我们还是按照二叉查找树的删除操作,删除结点1:

显然,这条路径上减少了一个黑色结点,而且结点2再怎么变色也解决不了。

这时候我们进入第三步,专门解决父子双黑的情况。

第三步:遇到双黑结点,在子结点顶替父结点之后,分成6种子情况处理。

子情况1,结点2是红黑树的根结点:

此时所有路径都减少了一个黑色结点,并未打破规则,不需要调整。

子情况2,结点2的父亲、兄弟、侄子结点都是黑色:

此时,我们直接把结点2的兄弟结点B改为红色:

这样一来,原本结点2所在的路径少了一个黑色结点,现在结点B所在的路径也少了一个黑色结点,两边“扯平”了。

可是,结点A以下的每一条路径都减少了一个黑色结点,与结点A之外的其他路径又造成了新的不平衡啊?

没关系,我们让结点A扮演原先结点2的角色,进行递归操作,重新判断各种情况。

子情况3,结点2的兄弟结点是红色:

首先以结点2的父结点A为轴,进行左旋:

然后结点A变成红色、结点B变成黑色:

这样的意义是什么呢?结点2所在的路径仍然少一个黑色结点呀?

别急,这样的变化有可能转换成子情况4、5、6中的任意一种,在子情况4、5、6当中会进一步解决。

子情况4,结点2的父结点是红色,兄弟和侄子结点是黑色:

这种情况,我们直接让结点2的父结点A变成黑色,兄弟结点B变成红色:

这样一来,结点2的路径补充了黑色结点,而结点B的路径并没有减少黑色结点,重新符合了红黑树的规则。

子情况5,结点2的父结点随意,兄弟结点B是黑色右孩子,左侄子结点是红色,右侄子结点是黑色:

这种情况下,首先以结点2的兄弟结点B为轴进行右旋:

接下来结点B变为红色,结点C变为黑色:

这样的变化转换成了子情况6。

子情况6,结点2的父结点随意,兄弟结点B是黑色右孩子,右侄子结点是红色:


首先以结点2的父结点A为轴左旋:

接下来让结点A和结点B的颜色交换,并且结点D变为黑色:

这样是否解决了问题呢?

经过结点2的路径由(随意+黑)变成了(随意+黑+黑),补充了一个黑色结点;

经过结点D的路径由(随意+黑+红)变成了(随意+黑),黑色结点并没有减少。

所以,这时候重新符合了红黑树的规则。

以上就是红黑树删除的全过程。

给定下面这颗红黑树,待删除的是结点17:

第一步,由于结点17有两个孩子,子树当中仅大于17的结点是25,所以把结点25复制到17位置,保持黑色:

接下来,我们需要删除原本的结点25:

这个情况正好对应于第二步的情况三,即待删除结点是黑色,子结点是空叶子结点。

于是我们删除框框中结点25,进入第三步:

此时,框框中的结点虽然是空叶子结点,但仍然可以用于判断局面,当前局面符合子情况5的镜像:

于是我们通过左旋和变色,把子树转换成情况6的镜像:

再经过右旋、变色,子树最终成为了下面的样子:

这样一来,整颗二叉树又重新符合了红黑树的规则。


往期推荐万字详解|手撕 9大排序算法!2020-09-11 URL 去重的 6 种方案!(附详细代码)2020-09-09 字符串操作的12个小技巧!2020-09-10 关注下方二维码,收获更多干货!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHP高并发高负载系统架构

2019独角兽企业重金招聘Python工程师标准>>> 一、高并发和高负载的约束条件 硬件部署操作系统Web 服务器PHPMySQL测试二、解决之道——硬件篇 处理能力的提升&#xff1a;部署多颗CPU&#xff0c;选择多核心、具备更高运算频率、更大高速缓存的CPU&#xff1b; 处理…

Java ObjectInputStream registerValidation()方法与示例

ObjectInputStream类registerValidation()方法 (ObjectInputStream Class registerValidation() method) registerValidation() method is available in java.io package. registerValidation()方法在java.io包中可用。 registerValidation() method is used to register an ob…

电脑系统越来越慢,怎么删除临时文件

1.关闭"休眠"方法:打开[控制面板]→[电源选项]→[休眠],把"启用休眠"前面的勾去掉说明:休眠是系统长时间一种待机状态,使您在长时间离开电脑时保存操作状态,如果您不是经常开着电脑到别处去的话,那就把它关了吧!☆立即节省:256M2.关闭"系统还原"…

线性方程组的矩阵表示_用矩阵表示线性方程组

线性方程组的矩阵表示A Linear Equation can be represented in matrix form using a: 线性方程可以使用以下形式以矩阵形式表示 &#xff1a; Coefficient Matrix 系数矩阵 Variable Matrix and 可变矩阵和 Constant Matrix 常数矩阵 The System of linear equation in three…

为easyui添加多条件验证

easyui的验证框架&#xff0c;validatebox不能有效的支持多个条件的验证&#xff0c;比如中文用户名&#xff0c;既要验证其是中文&#xff0c;又要验证其长度不超过6位时便显得很繁琐&#xff0c;需要反复的为easyui添加验证规则。 在此实现一个多个条件验证的验证规则&#x…

图解|查找数组中最大值的5种方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;我们在一些特定场景下&#xff0c;例如查询公司员工的最高薪资&#xff0c;以及班级的最高成绩又或者是面试中都会遇到查找最…

学习C语言,要从入门到精通

1、学习C语言&#xff0c;要从入门到精通&#xff0c;需要读哪些书&#xff08;从简单的到难的排序&#xff0c;越详细越好&#xff0c;最好都能注释下选择这本书的理由&#xff09;&#xff1f; 入门阶段&#xff1a;还是老谭那本。 、、理由&#xff1a;虽然不能说它写得有多…

程序设计爬楼梯问题_楼梯案例:解决楼梯问题的C ++程序

程序设计爬楼梯问题A child is running up a staircase with N steps, and can hop 1 step, 2 steps or 3 steps at a time. Implement a method to count how many possible ways the child can run up to the stairs? You need to return number of possible ways W. 一个孩…

JDK15正式发布,新增功能预览!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;JDK 15 在 2020 年 9 月 15 号正式发布了&#xff0c;这次发布的主要功能有&#xff1a;JEP 339&#xff1a;EdDSA 数字签名…

[LeetCode] Longest Consecutive Sequence 求解

为什么80%的码农都做不了架构师&#xff1f;>>> 题目 Given an unsorted array of integers, find the length of the longest consecutive elements sequence. For example, Given [100, 4, 200, 1, 3, 2], The longest consecutive elements sequence is [1, 2, …

怎么在Word中插入歌曲

1、菜单栏 -> 插入 -> 对象 -> windows media player -> 右键 -> 属性 -> 自定义 -> 选择歌曲完整路径 -> 选择模式 -> invisible&#xff08;使视频框隐藏&#xff09;退出设计模式最后别忘了保存2、菜单栏 -> 工具 -> 宏 -> 宏 -> 宏…

双向循环链表

双向循环链表是一种较为特殊的链表&#xff0c;也是一种常见的数据结构&#xff0c;其头尾相连&#xff0c;各节点之间可互相访问&#xff0c;在单链表中&#xff0c;只能依次向后访问&#xff0c;无法访问上一个节点&#xff0c;而双链表可以依次向下访问也可向上访问。 链表…

OkHttp透明压缩,收获性能10倍,外加故障一枚

要使用OkHttp&#xff0c;一定要知道它的透明压缩&#xff0c;否则死都不知道怎么死的&#xff1b;或者活也不知道为什么活的不舒坦。反正不是好事。什么叫透明压缩呢&#xff1f;OkHttp在发送请求的时候&#xff0c;会自动加入gzip请求头Accept-Encoding:gzip。所以&#xff0…

块元素、行内块和内联元素_如何删除内联块元素之间的空间?

块元素、行内块和内联元素Introduction: 介绍&#xff1a; This question has become rather popular. How does one remove whitespaces between the inline-block elements? The interesting thing is there are numerous solutions to this but not all of them are easy …

Spring--quartz中cronExpression 的配置方法

Spring--quartz中cronExpression Java代码 字段 允许值 允许的特殊字符 秒 0-59 , - * / 分 0-59 , - * / 小时 0-23 , - * / 日期 1-31 , - * ? / L W C 月份 1-12 或者 JAN-DEC , - * /…

C语言图形库——EasyX基本贴图

在C语言的学习过程中&#xff0c;接触最多的就是黑乎乎的DOS窗口&#xff0c;这也是在消磨学习者的兴趣&#xff0c;学到最后可能还不知道C语言到底能做什么&#xff0c;难道就是输入输出数据吗&#xff1f;当然不是&#xff0c;C的用处很广泛&#xff0c;这里不做讨论。我们能…

HTML5-特效

HTML5-特效-跟随鼠标的粒子<!DOCTYPE html> <html lang"en"><head><meta charsetutf-8><title>Liquid Particles - spielzeugz.de canvas experiment </title><meta name"description" content"HTML5/canvas …

一气之下,手撸了一个抖音去水印的工具!

百因必有果说一下我为什么要做个抖音视频去水印工具&#xff0c;其实是因为我的沙雕女友&#xff0c;她居然刚我~有天晚上她在抖音看见一个非常具有 教育意义 的视频&#xff0c;“男人疼媳妇就该承包全部家务活”&#xff0c;然后它就想把视频下载下来&#xff0c;分享到她的姐…

css 隐藏元素 显示元素_使用CSS打印时如何隐藏元素?

css 隐藏元素 显示元素Introduction: 介绍&#xff1a; We have come across many challenges while developing a website or web page and every challenge comes with new learnings. It is a trait of a good developer who develops or creates websites or web pages by…

C语言图形库——EasyX常用函数

上节讲到贴出一张图片的过程&#xff0c;本节接着介绍一些基本的图形库函数。 头文件 #include <graphics.h>1、图形窗口背景颜色设置函数&#xff1a; 例 setbkcolor(YELLOW)&#xff1b;//将图形窗口背景颜色设置为黄色。也可用 setbkcolor(RGB(180,24,137));利用三…