半小时看懂红黑树——全网最易理解教程

Posted 纵横千里,捭阖四方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了半小时看懂红黑树——全网最易理解教程相关的知识,希望对你有一定的参考价值。

相信很多人都知道红黑树,就是结点有红色和黑色两种。在Linux内存管理、java的Map里都大量使用了红黑树。那到底啥是红黑树,为什么会有红黑树呢?用AVL树不香吗?

关于什么是红黑树,有一个很出名的段子。某猿去一大厂面试,面试官就问什么是红黑树,该猿没有答上来。最后面试接近尾声,面试官象征性问是否还有其他问题的时候,该猿就说,请问红黑树是啥呢?结果面试官说:我也不记得了。

为啥会这样,因为在太多的材料里一提到红黑树就甩出5大条件,然后就是一堆的解释:

  1. 每个节点或者是黑色,或者是红色。
  2. 根节点是黑色。
  3. 每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
  4. 如果一个节点是红色的,则它的子节点必须是黑色的。
  5. 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

看到这5点, 估计没有人搞懂什么是红黑树,因为连看的欲望都没有,所以这样介绍红黑树是极不负责任的。我甚至都怀疑这么写的人是否真的能记住。

到底什么是红黑树呢?找啊找,在一个教程里提到说《算法》这本书的介绍最好,我就结合两者仔细看,感觉是真正看懂了。而被推荐的这本书的作者就是红黑树的发明者,而这位老爷子也是鼎鼎大名的《计算机程序设计的艺术》的作者高德纳的学生。有时候真感觉只有懂的人才能说出让人听懂的话。

这本书没有上来就给一堆红黑树的特性,而是先介绍了2-3树,最后介绍如何用红黑树来简化2-3,也就是说2-3树和红黑树是相通的,理解2-3树很容易 ,通过2-3理解红黑树也就容易很多了,所以我们也先从2-3树开始。

 

1.什么是2-3树

2-3树首先满足二分搜素树的基本性质。二分搜索树我们前面分析过,其基本性质是中序遍历正好是有序的。2-3树的不同之处是一个结点可以存一个元素也可以存两个,例如

 对于右侧的结点,一个父节点就可有两个三个孩子,三个孩子的元素分布分别是小于b,b和c之间,以及大于c。

因为一个结点可以又两个也可以都三个孩子,所以就叫2-3树。

这样一个2-3树就可能由两种结点组成。如下图:

 2-3树有一个非常重要的性质:一定是绝对平衡的树。也就是深度都是一样的,那是怎么做到的呢?请看下一节。

2.理解2-3树如何做到一定平衡的

原则是:元素插入过程,数量超过2的时候,先融合再分裂,而不会将元素直接插入到空结点。

我们现在就通过一个构造的例子来看,假如序列是42 ,37,12  ,18,6,11,5,我们来构造一个2-3树。

首先插入元素为42和37的时候,因为2-3树一个节点可以放两个元素,因此此时结构为:

如果此时12进来了,则首先融合成一个具有3元素的结点:
 

然后再根据平衡树类似的原理分裂:

 如果此时再来一个元素 18,会怎么样呢?首先根据平衡树的原则,18比37小,会插入到其左子树中,此时12位置只有一个元素,还能插入一个,所以就变成了这样子:

如果此时再来一个元素6,会怎么样呢?很明显此时结点元素数量超了,此时会先和12、18位置临时融合成如下结构:
 

之后再分裂,按照我们的正常理解,应该会变成这样子:

很明显,此时不是绝对平衡的,那该怎么办呢?此时12要和上面的元素融合,变成这样的结构;

此时又是绝对平衡了。

如果此时再增加11呢? 11小于12,要到左子树上去,而6位置只有一个元素,所以就是这样:

如果此时再来一个元素5呢?根据我们前面的分析,要先和6、11融合成这样:

 此时最左下结点元素超了,要执行分裂,我们理解应该是这样:

 但是此时又不是绝对平衡了,所以,6要和父节点融合成这样:

但是此时根元素也超了,需要进一步分裂 ,就变成这样

这样就重新变成绝对平衡了。这样貌似都是2树了,是否可以合并一下让某些节点可以放两个元素呢?上面的树依然保持2-3树的性质,没必要再合并了。

小结

从上面我们可以看到,如果待插入的结点只有一个元素,可以直接插入。如果已有两个了,则先暂时融合,再分裂开。

如果分裂之后导致树不平衡了,则需要考虑向父节点融合。例如下面的过程插入4之后的变化过程:
 如果说根节点元素也超了,此时会分裂,导致树增加了一层。例如下面这个结构插入4之后的样子

 

3.红黑树如何与2-3树等价的 

上面我们说2-3树就是一个节点可以有两个或者三个元素的绝对平衡树。

 也就是如下的样子:

 上面的结构有个坏处是每个节点可能有2个或者三个子树,这会给查找等带来麻烦,实现也比较复杂,那是否可以用二叉树表示上面这种结构呢?

其实bc节点连接3个子孩子可以这样表示:让前两个自孩子都连接到b上,如下:

 然后再将b-c调整一下关系,此时就是下面这样子:

 很明显b的地位变成c的子节点了,那此时怎么知道b和c本来是在一次的呢?很简单,我们将b的颜色给换一下:

 这就是红黑树的由来。红和黑只是一个状态标记而已,本质上就是用一个二叉树来表示2-3树。

由于红色节点是从2-3树种左侧那个分下来的,所以所有的红色节点都是在左子树上(也称为向左倾斜)。

我们再来看一个更复杂点的对应图:

上面的红黑树种有三个红色节点,正好对应的就是原来2-3树中有两个元素的结点的数量。

看到了吧,红黑树就这么简单。如果感觉还是不太懂,我们可以先增加一个中间状态树:

 4.解释开篇那5条规则

(1)每个节点或者是黑色,或者是红色

这个就是红黑树的定义,但是这里我们要明白红色表示的其实是在2-3树中,有两个元素的结点靠左的那一个。


(2)根节点是黑色

为什么根节点一定是黑色的呢?因为只有一个节点出现两个元素的时候左侧的向下并标记为红色,留下的是黑色的。所以根节点一定是黑色的。


(3)每个叶子节点(NIL)是黑色

  [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]

因为每个叶子结点只有一个元素嘛,不可能为红色的。

不过我没明白这里的空是啥意思,叶子结点指向为空吗?


(4)如果一个节点是红色的,则它的子节点必须是黑色的。

理解了上面的转换关系,这个其实也非常好理解了,因为红色节点下面连的结点不管是否发生了分裂融合,红色的两个指针,也就是图中1和2标记的位置一定是指向子树靠右的那一个元素,必然是黑色的。


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

 前面4条都是废话,而这一条是红黑树最重要的性质,也是为什么要造一个邪乎的红黑树出来的原因。

这一条从红黑树的角度来看仍然不是那么好理解,但是从与之等价的2-3树就非常直观了:

从上面可以看到,访问叶子结点 12、18、37、48、88需要访问的黑色结点要么是42、33,要么是42、50。所以说访问的黑色结点数是一样的。

其实红黑树还有颜色反转和右旋的逻辑,后面再看要不要补充。

5.面试时怎么回答红黑树

我觉得红黑树理解这些内容就差不多了。在面试过程中如果谈到HaspMap以及并发性时,可能会涉及。如果你真的懂 ,不妨引导一下让面试官问你红黑树。毕竟你自己引导他问你熟悉的问题,比他随便找你不熟悉的问题要好很多。

如果真的问你红黑树了,该怎么办呢?红黑树的问题不过是 什么是红黑树,为什么要用红黑树,红黑树的特征是什么,以及如何构造红黑树几个问题。

如果面试官问你红黑树了,你不要急着背那5条规则,背不下来,也没人愿意听。

你应该先说“要解释红黑树,首先应该明白为什么要有红黑树。”

面试官自然会问你:那为什么Map里要用红黑树。

你接着说:是因为使用二叉树存储时,不对其进行平衡操作,可能会导致树退化成线性的结构。而如果严格保持树要平衡,因为其调整的代价比较高,所以会影响执行的效果。而红黑树本质是一种半平衡的树。红黑树的特征是任何一个结点的左右子树的高度差小于两倍,这实现了查找效率和操作性能的平衡。

然后面试官会很自然的问:红黑树如何保持的。

你可以回答:要解释红黑树,应该先从2-3树开始。然后就是简要说一下上面的对应原理。最后就说:所以,颜色只是节点的一个标记字段,红色节点就是表示与父节点是同一级的。也正是因为如此,我们可以知道红黑树有5个特征。

如果期间面试官没有说话,说到这里,你一定要停下来,问一下:我要解释一下红黑树的5大特征吗?为什么要停下来?因为不见得面试官真正了解红黑树,更极少会从2-3一步步清晰理解红黑树,说道这里,需要给他时间消化一下。如果你不停地说,他会啥也记不住了。

然后你就可以从两者的关系简要说明5条规则,其中第五条是最重要的,但是用2-3解释的话,一句话就搞定了。如果说道这里,我估计面试官不会再说什么。

这样一轮下来,整个过程完全由你主导,而你的思维能力也得到了很好的体现,这才是比较好的面试。

红黑树的代码也不必写,因为太复杂。如果面试的时候让你写红黑树插入和删除的逻辑,那你就要考虑他是不是不想要你,想刁难你一下让你走。

以上是关于半小时看懂红黑树——全网最易理解教程的主要内容,如果未能解决你的问题,请参考以下文章

这 30 张图带你读懂红黑树

不能白板编程红黑树就是基础差?别扯了。

红黑树的插入操作过程详细图解

一文看懂 HashMap 中的红黑树实现原理

红黑树是怎么实现的,看这篇真的就够了!

五分钟搞懂什么是红黑树(全程图解)