红黑树转化过程

红黑树转化过程

添加操作宏观过程:首先将红黑树当作一颗查找树一样将结点插入,然后将结点着为红色,最后通过旋转和重新着色的方法使之重新成为红黑树

将新加入的结点涂成红色的原因:

1)不违背红黑树的性质5:从任意一个结点出发到空叶子结点,经过的黑色结点个数相同

2)按照红黑树的性质4我们知道红黑树中黑结点的个数至少是红结点个数的两倍,所以新增结点的父亲结点是黑结点的概率比较大,如果新增结点的父节点为黑色,那么此时不需要再去进行任何调整操作,因此效率很高,所以新结点应该涂成红色

少违背一条性质,意味着我们后续的旋转和重新着色操作会简单很多

现在我们来看看新增一个红色的结点会违背红黑树的5条性质中的哪些?

1)每个结点或红或黑

2)根结点是黑色

3)空叶子结点是黑色

4)如果一个结点是红色,那么它的子节点是黑色

5)从任意一个结点出发到空的叶子结点经过的黑结点个数相同

1.显然没有违背

2.根据查找树的特定,插入操作不好改变根结点,所以也没有违背

3.插入的肯定不是空叶子结点,所以也没有违背

4.有可能违背!!!

5.插入结点涂成红色就是为了不违背第5条性质

现在我们来分析一下新增的结点(红色)插入之后可能面临的几种情况,以及他们的处理措施

1.插入的结点为根结点

将新插入的红色结点变成黑色结点,满足根结点为黑色结点的要求!

2.父亲结点为黑色结点

这个时候不需要进行任何调整操作,此时的树仍然是一颗标准的红黑树

3.父亲结点为红色结点的情况下,叔叔结点为红色结点(不用考虑左右)

解决方案:将叔叔和父亲结点改为黑色,爷爷结点改为红色,未完

然后又将爷爷结点当作插入结点看待,一直进行上面的操作,直到当前结点为根结点,然后将根结点变成黑色

原图:

图4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fqQsbb63-1688050658852)(assets\1301290-20190418213129039-1750834042.jpg)]

插入一个125的结点:

图5

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CdeHtKvr-1688050658853)(assets\1301290-20190418213129777-667737935.jpg)]

现在125结点和130结点都是红色的,显然违背了规则4,所以将新插入结点的父亲130结点和插入结点的叔叔结点150变成黑色,并将新插入结点的爷爷结点140变成红色,图如下:

图6

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LNRRdWcc-1688050658854)(assets\1301290-20190418213130624-539000870.jpg)]

然后又将140结点当作新插入结点处理(因为140结点和新插入结点面临的情况都是一样的:和父亲结点都是红色),也就是做如下处理:将140结点的父亲结点120和140的叔叔结点60变成黑色结点,将140结点的爷爷结点变成红色,因为遍历到了根结点,要满足根结点是黑色的性质要求,所以又将140的爷爷结点也就是根结点变成黑色,图如下:

图7

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vBjaHSP3-1688050658855)(assets\1301290-20190418213131667-1276564969.jpg)]

到这里,为新插入结点125所做的某些结点重新着色的操作就完成了,现在该树是标准的红黑树了!

4.新插入的结点的父亲结点为红色,其叔叔结点为黑色,

1)父亲结点为爷爷结点的左孩子,新插入结点为父节点的左孩子(左左情况)

2)父亲结点为爷爷结点的右孩子,新插入结点为父亲结点的右孩子(右右情况)

上述两种情况都是同一个处理办法

比如下图,新插入结点为25,其父亲结点30为红色,其叔叔结点为空黑色叶子结点,且新插入结点和其父节点都是左孩子:

图8

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FwoLTjw6-1688050658856)(\assets\1301290-20190418213133079-1448372531.jpg)]

我们将其父亲结点和爷爷结点颜色互换,然后针对爷爷结点进行一次左旋,图如下:

图9

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ZEkd17X-1688050658856)(assets\1301290-20190418213134136-940254682.jpg)]

现在这颗树完全满足红黑树的5个性质了(最好自己对照5个性质看一下)

现在又一个问题,我们为什么要进行旋转?

假设我们只将新增结点的父亲结点和其爷爷结点的颜色互换了,图如下:

图10

Inked红黑树(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213136770-843083460.jpg)_LI

我们发现上述两条到叶子结点的路径经过的黑色结点数量不一样!!!,所以它不满足红黑树的第5条性质,所以这就是我们旋转的意义所在!!!(因为无论你这么旋转都没有改变结点颜色,改变的是结点的位置,而这位置改变刚好能使得树满足红黑树的第5条性质!)

5.新插入的结点的父亲结点是红色,其叔叔结点是黑色

1)插入结点是右结点,父节点是左结点

2)插入结点是左结点,父亲结点是右结点

上述两种情况都是同一个处理办法

比如下图,新插入结点是126,其父结点125为红色,其叔叔结点为空的黑色结点,而且插入结点是右结点,父结点是左结点

图11

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zKsURS7B-1688050658857)(\assets\1301290-20190418213137634-1958102851.jpg)]

我们将父亲结点125看作当前结点进行左旋,旋转结果如下:

图12

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L2vcGkN4-1688050658858)(\assets\1301290-20190418213139039-597178902.jpg)]

现在我们的当前结点是125,现在125的处境和上面的情况4是一样的(父节点为红,叔叔结点为黑,插入结点为左结点,父亲结点也为左孩子)现在我们继续按照情况4的处理办法处理上述情况(措施和情况4一样,父亲结点和爷爷结点互换颜色,然后针对爷爷结点进行左旋),处理后情况如下:

图13

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-44MCMg6N-1688050658858)(\assets\1301290-20190418213140154-225773995.jpg)]

现在树就是一颗标准的红黑树了!

我们现在总结一下插入结点面临的几种情况以及采取的措施:

1.树为空,插入的结点为根结点

直接将插入的结点变成黑色

2.父亲结点为黑色结点

不需要任何操作

3.父亲结点为红色结点的情况下:

3.1 叔叔结点也为红色结点

将叔叔和父亲结点改为黑色,爷爷结点改为红色,未完,然后又将爷爷结点当作插入结点看待,一直进行上

面的操作,直到当前结点为根结点,然后将根结点变成黑色

3.2 叔叔结点为黑色结点的情况下:

​ 3.2.1 (父亲结点为左孩子,插入结点也为左孩子)||(父亲结点为右孩子,插入结点也为右孩子)

​ 将父亲结点和爷爷结点的颜色互换,然后针对爷爷结点进行一次左旋

​ 3.2.2 (父亲结点为左孩子,插入结点为右孩子)||(父亲结点为右孩子,插入结点为左孩子)

​ 针对父结点进行左旋,此时左旋后的情况必定是3.2.1的情况,然后按照3.2.1的情况处理

现在我们来讨论一下,为什么插入的情况只有上面这些:

1.爷爷结点为红色结点的情况下,父亲结点只能为黑色(红黑树的性质4),处理操作:上面情况2

2.爷爷结点为黑色的情况下,父亲结点和叔叔结点:可以为红色,也可以为黑色

2.1 父亲结点为黑,叔叔结点为黑:处理操作:上面情况2

2.2 父亲结点为黑,叔叔结点为红:处理操作:上面情况2

2.3 父亲结点为红,叔叔结点为红:处理操作:上面情况3.1

(上面3种情况都是不用考虑左右的)

2.4 父亲结点为红,叔叔结点为黑:

2.4.1 父亲结点为左孩子,叔叔结点为左孩子:处理操作:上面情况3.2.1

2.4.2 父亲结点为右孩子,叔叔结点为右孩子:处理操作:上面情况3.2.1

2.4.3 父亲结点为左孩子,插入结点为右孩子:处理操作:上面情况3.2.2

2.4.4 父亲结点为右孩子,插入结点为左孩子:处理操作:上面情况3.2.2

总结:可以发现我们没有遗漏任何情况,所有可能面临的情况我们都处理了

五.红黑树之删除结点

先说一个删除结点的过程原理:首先将红黑树当作一个二叉查找树,将该结点从二叉查找树种删除,然后通过一些列重新着色操作等一系列措施来修正该树,使之重新成为一颗红黑树

删除结点其实很容易,难的是如何使得删除结点后的树重新成为一个红黑树

我们可以根据删除结点N的儿子个数分为三种情况:

1.删除结点没有儿子

2.删除结点有1个儿子

3.删除结点有2个儿子

接下来我们又可以对以上三种情况继续进行细分

一.删除结点没有儿子的情况:

1)删除结点为红色

2)删除结点为黑色,其兄弟结点没有儿子

3)删除结点为黑色,其兄弟结点有一个孩子不空,并且该孩子为右孩子

4)删除结点为黑色,其兄弟结点有一个孩子不空,并且该孩子为左孩子

5)删除结点为黑色,其兄弟结点有两个孩子,而且兄弟结点为红色

6)删除结点为黑色,其兄弟结点有两个孩子,而且兄弟结点为黑色

二.删除结点只有一个儿子的情况:

1)删除结点为黑色,其唯一的儿子结点为红色(必定是红色,要不然不符合红黑树的第5条性质)

2)删除结点为红色,其儿子结点只能为黑:红黑树中不存在这种情况,要不然无法满足红黑树第5条性质

三.删除结点有两个儿子的情况:

现在我们就具体分析一下面临不同的操作到达该这么操作:

一.删除结点没有儿子的情况:

1)删除结点为红色

直接删除,比如下图,想要删除130结点

图14

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-12XwvJKM-1688050658859)(\assets\1301290-20190418213143002-1972356300.jpg)]

直接删除130结点,结果图如下:

图15

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213143907-1237419880.jpg)

因为删除的是红色结点,不会影响红黑树第5条性质,所以可以直接删除

2)删除结点为黑色,其兄弟结点没有儿子

这种情况下其兄弟结点也肯定是黑色的(要满足红黑树第5条性质),假设现在要删除的是150这个结点,原图如下:

图16

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213144640-886967587.jpg)

先删除结点150,然后将兄弟结点126变成红色,父亲结点140变成黑色,结果如下:
图17

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213145413-74677869.jpg)

这样做的目的是为了满足红黑树的第5条性质,要不然根到最右边的叶子结点经过的黑色结点只有3个,而其他路径有4个

3)删除结点为黑色,其兄弟结点有一个孩子不空,并且该孩子和兄弟结点在同一边(同为左子树或者同为右子树)

假设现在要删除的结点为110,其兄弟结点140只有一个孩子150,而且都是右子树,满足上述条件,原图如下:

图18

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213146047-331676828.jpg)

先把需要删除的结点110删除,然后这个时候需要交换兄弟结点140和父亲结点120的颜色,并且把父亲结点120涂成黑色,把兄弟结点的子节点150涂成黑色

1.如果兄弟结点和兄弟结点的儿子都在右子树的话:对父亲结点进行左旋

2.如果兄弟结点和兄弟结点的儿子都在左子树的话:对父亲结点进行右旋

上图是第一种情况,所以对父结点120进行左旋,结果如下:

图19

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213146883-809046894.jpg)

通过对某些结点重新着色和旋转,又将该树变成了一个标准的红黑树了

4)删除结点为黑色,其兄弟结点有一个孩子不空,并且该孩子和兄弟结点不在同一边(右左或者左右的情况)

(这种情况下,兄弟结点的儿子50结点只能为红色,要不然满足不了红黑树的第5条性质)

假设我们现在要删除的结点是80结点,其兄弟结点只有一个儿子,而且兄弟结点和兄弟结点的儿子是左右的情况(兄弟结点为左结点,兄弟结点的儿子为右结点),符合上述要求,原图如下:

图20

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213147585-336052673.jpg)

现在我们先将需要删除的80结点删除,然后将兄弟结点和兄弟结点的儿子结点颜色互换

如果兄弟结点是左子树,兄弟结点的儿子结点是右子树:对兄弟结点进行左旋

如果兄弟结点是右子树,兄弟结点的儿子结点是左子树:对兄弟结点进行右旋

上图的情况是进行左旋,也就是对兄弟结点30进行左旋,结果如下图:

图21

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213148409-1345914502.jpg)

注意!!,现在还没有结束变换,我们发现变换之后的红黑树情况和情况3中的情况很相似,兄弟结点50和兄弟结点的子节点30处在同一边,我们可以按照情况3的处理办法进行处理:

交换兄弟结点50和父亲结点60的颜色,把父亲结点60和兄弟结点的子节点30涂成黑色

1.如果兄弟结点和兄弟结点的儿子都在右子树的话:对父亲结点进行左旋

2.如果兄弟结点和兄弟结点的儿子都在左子树的话,对父亲结点进行右旋

上图的情况是第2中,所以对父亲结点60进行右旋,结果如下:

图22

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213826098-454745347.jpg)

5)删除结点为黑色,其兄弟结点有两个孩子,兄弟结点为黑色而且两个孩子结点也为黑色

现在我们假设要删除的结点是130结点,其兄弟结点有两个孩子(可以把空的叶子结点看成黑色的儿子结点),而且兄弟结点和兄弟结点的儿子结点都是黑色,符合上述情况,原图如下:

图23

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213826841-45465719.jpg)

先直接删除需要删除的结点130,然后将父亲结点140和兄弟结点150颜色互换即可,结果如下:

图24

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213827464-669837359.jpg)

6)删除结点为黑色,其兄弟结点有两个孩子,而且兄弟结点为红色

假设我们要删除的结点是110,其兄弟结点140为红色而且有两个孩子,原图如下:

图25

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213828198-1874419200.jpg)

我们先交换兄弟结点140和父亲结点120的颜色

1.被删除的元素为左子树:对父亲结点左旋

2.被删除的元素为右子树:对父亲结点右旋

上图的情况是第一种情况,所以我们对父亲结点140进行左旋,按照上面操作之后(未完),结果如下:

图26

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213828905-466826326.jpg)

我们发现完成上述操作之后树还不是一个标准的红黑树(到叶子结点的一条路径黑色结点只有3个,而其他的路径有4个),我们发现现在红黑树的情况又和情况5的很像,所以我们按照情况5的做法继续:

我们要需要删除的结点还没有被删除(我特意留到最后删除的,就是为了在这里表示父亲结点是谁的父亲结点…),现在我们将父亲结点120和兄弟结点130的颜色互换即可,结果如下:

图27

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213829608-385779842.jpg)

我们现在对删除结点没有儿子结点的6种删除情况进行一下总结:

删除结点没有儿子结点:

1)删除结点为红色:

直接删除

2)删除结点为黑色,其兄弟结点没有儿子:

兄弟结点变红,父亲结点变黑,然后将父亲结点当作当前结点按照这几种情形处理,直到当前结点为根结点

3)删除结点为黑色,其兄弟结点有一个孩子不空,并且该孩子和兄弟结点在同一边(同为左子树或者同为右子树):

1.不管是括号中那种情况,先交换兄弟结点和父亲结点的颜色,并且把父亲结点和兄弟结点的子结点涂成黑色

2.1如果兄弟结点和兄弟结点的儿子都在右子树的话:对父亲结点进行左旋

2.2如果兄弟结点和兄弟结点的儿子都在左子树的话:对父亲结点进行右旋

4)删除结点为黑色,其兄弟结点有一个孩子不空,并且该孩子和兄弟结点不在同一边(右左或者左右的情况):

1.先将兄弟结点和兄弟结点的儿子结点颜色互换

2.1如果兄弟结点是左子树,兄弟结点的儿子结点是右子树:对兄弟结点进行左旋

2.2如果兄弟结点是右子树,兄弟结点的儿子结点是左子树:对兄弟结点进行右旋

3.将后续变换按照第3条处理

5)删除结点为黑色,其兄弟结点有两个孩子,兄弟结点为黑色而且两个孩子结点也为黑色:

1.将父亲结点和兄弟结点颜色互换

6)删除结点为黑色,其兄弟结点有两个孩子,而且兄弟结点为红色:

1.将兄弟结点和父亲结点的颜色互换

2.1 被删除的元素为左子树:对父亲结点左旋

2.2 被删除的元素为右子树:对父亲结点右旋

3.将后续变换按照第5条进行处理

以上6种情况讨论的都是删除结点没有儿子的情况(空叶子结点不算儿子结点)

现在我们来看看删除结点仅有一个儿子结点的情况!

二.删除结点仅有一个儿子结点的情况

1)删除结点为黑色,儿子结点无论左右都可以

比如我们要删除的结点是120结点,删除结点为黑色,唯一的儿子结点130为红色(必须是红色,不然违背红黑树第5条性质)原图如下:

图28

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213830431-836031235.jpg)

我们将需要删除的结点120删除,然后将子节点130涂黑放到被删除结点120的位置,结果如下:

图29

assets\1301290-20190418213831046-1031506610.jpg)

2)删除结点为红色:其儿子结点只能为黑,红黑树中不存在这种情况,要不然无法满足红黑树第5条性质

总结一下删除结点只有一个儿子的情况:

1)删除结点为黑色,儿子结点无论左右都可以

将儿子结点涂成黑色放到被删除结点的位置

下面我们来看看删除结点有两个儿子结点的情况

三.删除结点有两个儿子结点

找到删除结点的右子树中最左的结点,两两值交换,然后删除结点的情况就变成了上面两种情况中的一种了

1.删除结点只有一个儿子的情况

2.删除结点没有儿子的情况

比如下图

图30

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213831789-1881553616.jpg)

假设要删除的结点是120,先找到结点120右子树中最左的结点125,交换两者的值,图如下:

图31

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213832474-2085751065.jpg)

现在120仍然是要删除的结点,我们发现删除结点120没有一个儿子,而且其兄弟结点也没有儿子,那么其对应的情况为:

2)删除结点为黑色,其兄弟结点没有儿子:

兄弟结点变红,父亲结点变黑

经过上面的变形,结果如下:

图32

红黑树2(D:\课程研发\项目三加强课程\jdk集合\assets\1301290-20190418213833448-224931959.jpg)

经过变换,该树变成了一颗标准的红黑树

所以当删除结点右两个儿子结点的时候,我们只需要按照搜索二叉树的删除方法替换删除值,这样就可以将情况变成删除结点没有儿子结点或者1个儿子结点的情况处理了

猜你喜欢

转载自blog.csdn.net/NeverFG/article/details/131466157