Java集合源码分析(六):红黑树(RB Tree)

红黑树和平衡二叉树的构建思想是类似的,都是在插入过程中对二叉排序树进行调整,从而提升性能,它的增删改查均可以在O(lg N)内完成。

一、红黑树的定义

红黑树是一颗二叉排序树,除了具有二叉排序树的特点与性之外,还具有以下的一些性质:

1、 每个节点要么是黑色要么是红色

2、 根节点是黑色

3、 每个叶节点(NIL)是黑色(这里说的叶节点是指为空的叶子结点)

4、 如果一个节点时红色的,则它的两个儿子都是黑色的

5、 从一个节点到该节点的子孙节点的所有路劲上包含相同数目的黑节点

红黑树示例:

在这里插入图片描述
每个节点的最后都会是一个NIL节点,他是黑色的,但是通常来讲,画图时都会省略它,大家记得还有它就可以,只是我们省略了。

二、红黑树的是实现原理

红黑树的插入与删除和平衡二叉树也是类似的,也是每插入一个节点,都检查是否破坏了树的结构,然后进行调整,红黑树每个节点插入式都默认为红色,这样做可以降低黑高,也可以减少调整的次数。

三、用红黑树来插入元素

我们现将一个数组{1, 10, 9, 2, 3, 8, 7, 4, 5, 6},来把它变成一个红黑树!

1.首先插入1,此时树是空的,1就是根节点,而根节点是黑色的。

在这里插入图片描述
2.然后插入10,根据二叉排序树,它只能是1的右子树,在根据红黑树的定义,它是红色的。

在这里插入图片描述
3.当我们插入9时,这是就会打乱规则出现问题了

在上面提到的红黑树规则4 中,强调不能有两个相邻的红色结点,所以此时我们需要对其进行调整。具体怎么调整,这里我总会出两种情况:

出现两个相邻的红色节点时,先判断其叔叔节点(父节点的兄弟节点)是否为红色

a:叔叔节点为红色时,直接变色,叔叔节点和父节点从红色变为黑色,祖父节点从黑色变为红色,变完之后在看是否为根节点或还存在其他红色节点相邻的情况,如若存在,在判断
b:叔叔节点不是红色时,就采取左旋或者右旋的方式,旋转之后,在判断是否满足红黑树的性质,如果不满足。继续判断和操作

在这里插入图片描述

拿下面这张图举例,9的叔叔节点为空,也就是不为红色,这里我们对其右旋,得到下面这样
在这里插入图片描述
我们可以看到两个红色节点还是相邻的,并且10的叔叔节点不为红,所以这里左旋,旋转之后再根据红黑树的性质,根节点为黑色,就可以得到下面这张图

在这里插入图片描述
4.插入元素2
在这里插入图片描述
1和2都为红色,相邻了,然后我们在判断2的叔叔节点10位红色,所以不用旋转,直接变色–>2的父节点和叔叔节点都变为黑色,祖父节点变为红色
在这里插入图片描述
然而9位根节点,根节点必须为黑色,再将9变为黑色,得到下面这张图
在这里插入图片描述
5.我们在继续插入元素3
在这里插入图片描述
这里2和3为红,并且相邻,叔叔节点不为红色,这里需要左旋,旋转完之后,之前的父节点变为红色,现在的父节点变为黑色,得到以下这张图
在这里插入图片描述
之后的每一步我就不一 一把过程列出来了,小伙伴们可以依靠以上几个步骤和红黑树的性质总结出规律,然后自行去试着把剩下的过程和步骤去搞出来,这里我把最后的结果贴出来:

最终结果:

在这里插入图片描述
最后总结一下,在插入元素的过程中,我们可以看到,待插入节点和父节点之间的关系决定着是否需要转换,而叔叔节点决定着怎样转换。

根据以上的步骤,我们总结出以下几种情况:

1、 如果父结点是黑色,插入即可,无需调整。

2、 如果叔叔结点是红色,就把父结点和叔叔结点都转为黑色,祖父结点转为红色,将不平衡向上传递。

3、 如果叔叔结点是黑色或者没有叔叔结点,就看父结点和待插入结点的关系。如果待插入结点和父结点的关系,与父结点与祖父结点的关系一致,比如待插入结点是父结点的左孩子,父结点也是祖父结点的左孩子,就无需多次旋转。否则就先通过相应的旋转将其关系变为一致。

三、在红黑树中删除元素

要从一颗红黑树中删除一个元素,要从几个方面去考虑

1、 待删除元素没有孩子

这里的没有孩子是指没有值不为NIL的孩子。在这种情况下,如果删除的元素是红色的,可以直接删除,如果删除的元素是黑色的,那就需要进行调整了。

接下来就让我们来举一个栗子:

在这里插入图片描述

要从这个图中删除元素1,当我们删除完1后,2的左孩子为NIL,这条路上的黑色节点数就比其他支路少了,不满足红黑树的性质,所以就需要我们来做出调整。

在插入时,我们重点关注叔叔节点,但在删除元素时,我们得把重心从叔叔节点转到兄弟节点上来,也就是此时的4,4是红色的,就把他染成黑色,把父节点染成红色,得到下面这张图

在这里插入图片描述
然后我们在以2来左旋:
在这里插入图片描述
旋转后把父节点变为黑色,子节点变为红色 ,然后在删除1,删除红色节点时无影响

在这里插入图片描述
2、待删除元素有一个孩子时

根据红黑树的定义,我们可以推测,如果一个元素仅有一个孩子,那么这个元素一定是黑色的,而且其孩子是红色的。

为什么呢?

假设我们有一个红色节点,它是树中的某一个节点,且仅有一个孩子,那么根据红色节点不能相邻的条件,它的孩子一定是黑色的,如下所示:

在这里插入图片描述
但这个子树的黑高却不再平衡了(注意每个节点的叶节点都是一个NIL节点),因此红色节点不可能只有一个孩子。

而若是一个黑色节点仅有一个孩子,如果其孩子是黑色的,同样会打破黑高的平衡,所以其孩子只能是红色的,如下所示:
在这里插入图片描述

只有这一种情况符合红黑树的定义,这时要删除这个元素,只需要使用其孩子代替它,仅代替值而不代替颜色即可,上图的情况删除完后变为:
在这里插入图片描述

可以看到,树的黑高并没有发生变化,因此也不需要进行调整。

3、待删除元素有两个孩子

我们在讨论二叉排序树时说过,如果删除一个有两个孩子的元素,可以使用它的前驱或者后继结点代替它。因为它的前驱或者后继结点最多只会有一个孩子,所以这种情况可以转为情况1或情况2处理。

四、总结

我们可以看出,最复杂的情况为第一种,这主要由其兄弟结点以及兄弟结点的孩子颜色共同决定。

接下来我么来分类总结下

我们以N代表当前待删除节点,以P代表父结点,以S代表兄弟结点,以SL代表兄弟结点的左孩子,SR代表兄弟结点的右孩子,如下所示:
在这里插入图片描述
根据红黑树定义,这种情况下S要么有红色的子结点,要么只有NIL结点,以下对S有黑色结点的情况均表示NIL

我们将情况分类,主要有以下几种:

1、 S是红色,P一定是黑色,S也不会有红色的孩子
在这里插入图片描述
我们将P和S颜色对换,在左旋
在这里插入图片描述
变换之后,N支路上的黑色节点并没有增加,还少一个。

2、P,S以及S的全部孩子都是黑色
在这里插入图片描述
我们把S染为红色,这样一来,N和S两个支路都少了一个黑色结点,所以可以把问题向父结点转移,通过递归解决
在这里插入图片描述
3、P为红(S一定为黑),S的孩子都为黑

只需要把P和S颜色交换即可。这样N支路多了一个黑色元素,而S支路没有减少,所以达到了平衡。

在这里插入图片描述
在这里插入图片描述

4、P任意色,S为黑,N是P的左孩子,S的右孩子SR为红,S的左孩子任意

在这里插入图片描述
此时将S改为P的颜色,SR和P改为黑色,然后再左旋
在这里插入图片描述
从中可以看出,此时N支路多了一个黑色结点,而其余支路均没有收到影响,所以调整完毕,P任意色,S为黑,N是P的左孩子,S的左孩子SL为红,S的右孩子SR为黑,
在这里插入图片描述
此时变换S和SL的颜色,然后右旋,得到下面这张图:
在这里插入图片描述
这时,我们可以看到,所有分支的黑色节点数没有改变,但情况5变味了情况四,不过在进行一次操作即可,没什么大毛病。

最后

红黑树的一些操作真的听复杂的,而且非非非非常常常常常有难度,但这些操作的目的都只有一个,那就是保证红黑树的结构不被破坏,以上所说的过程,大家可以自行上手操作一番,加深影响和理解,也可以自己去找一些相关书籍在来更深入的学习!

欢迎大家留言讨论!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值