今天咱们要说的红黑树就是就是一棵非严格均衡的二叉树,均衡二叉树又是在二叉搜索树的基础上增长了自动维持平衡的性质,插入、搜索、删除的效率都比较高。红黑树也是实现 TreeMap 存储结构的基石。性能
二叉搜索树又叫二叉查找树、二叉排序树,咱们先看一下典型的二叉搜索树,这样的二叉树有何规则特色呢?学习
二叉搜索树有以下几个特色:spa
下图就是一棵典型的二叉搜索树:3d
在这里插入图片描述
二叉搜索树是均衡二叉树的基础,咱们看一下它的搜索步骤如何。咱们要从二叉树中找到值为 58 的节点。blog
第一步:首先查找到根节点,值为 60 的节点。排序
在这里插入图片描述
第二步:比较咱们要找的值 58 与该节点的大小。教程
若是等于,那么恭喜,已经找到;若是小于,继续找左子树;若是大于,那么找右子树。图片
很明显 58<60,所以咱们找到左子树的节点 56,此时咱们已经定位到了节点 56。 资源
在这里插入图片描述it
第三步:按照第二步的规则继续找。
58>56 咱们须要继续找右子树,定位到了右子树节点 58,恭喜,此时咱们已经找到了。
在这里插入图片描述
咱们通过三步就已经找到了,其实就是咱们平时所说的二分查找,这种二叉搜索树好像查找效率很高,但一样它也有缺陷,以下面这样的二叉搜索树。
在这里插入图片描述
看到这样的二叉搜索树是否很别扭,典型的大长腿瘸子,但它也是二叉搜索树,若是咱们要找值为 50 的节点,基本上和单链表查询没多大区别了,性能将大打折扣。
这个时候咱们的均衡二叉树就粉墨登场了,均衡二叉树就是在二叉搜索树的基础上添加了自动维持平衡的性质。
上面的大长腿瘸子二叉搜索树通过自动平衡后,可能就成为了下面这样的二叉树。
在这里插入图片描述
通过了自动平衡,再去找值为 50 的节点,查找性能将提高不少。红黑树就是非严格均衡的二叉搜索树。
红黑树具体有哪些规则特色呢?具体以下:
**1. 节点分为红色或者黑色。
规则看着好像挺多,没错,由于红黑树也是均衡二叉树,须要具有自动维持平衡的性质,上面的 6 条就是红黑树给出的自动维持平衡所须要具有的规则。
咱们看一看一个典型的红黑树究竟是什么样儿?
在这里插入图片描述
首先解读一下规则,除了字面上看到的意思,还隐藏了哪些意思呢?
①从根节点到叶子节点的最长路径不大于最短路径的 2 倍
怎么样的路径算最短路径?从规则 5 中,咱们知道从根节点到每一个叶子节点的黑色节点数量是同样的,那么纯由黑色节点组成的路径就是最短路径。
什么样的路径算是最长路径?根据规则 4 和规则 3,如有红色节点,则必然有一个链接的黑色节点,当红色节点和黑色节点数量相同时,就是最长路径,也就是黑色节点(或红色节点)*2。
②为何说新加入到红黑树中的节点为红色节点
从规则 4 中知道,当前红黑树中从根节点到每一个叶子节点的黑色节点数量是同样的,此时假如新的是黑色节点的话,必然破坏规则。
但加入红色节点却不必定,除非其父节点就是红色节点,所以加入红色节点,破坏规则的可能性小一些,下面咱们也会举例来讲明。
什么状况下,红黑树的结构会被破坏呢?破坏后又怎么维持平衡,维持平衡主要经过两种方式【变色】和【旋转】,【旋转】又分【左旋】和【右旋】,两种方式可相互结合。
下面咱们从插入和删除两种场景来举例说明。
当咱们插入值为 66 的节点时,红黑树变成了这样:
在这里插入图片描述
很明显,这个时候结构依然遵循着上述 6 大规则,无需启动自动平衡机制调整节点平衡状态。
若是再向里面插入值为 51 的节点,这个时候红黑树变成了这样:
在这里插入图片描述
很明显如今的结构不遵循规则 4 了,这个时候就须要启动自动平衡机制调整节点平衡状态。
咱们能够经过变色的方式,使结构知足红黑树的规则:
**1. 首先解决结构不遵循规则 4 这一点(红色节点相连,节点 49-51),需将节点 49 改成黑色。
最终调整完成后的树为:
在这里插入图片描述
但并非何时都那么幸运,能够直接经过变色就达成目的,大多数时候还须要经过旋转来解决。
如在下面这棵树的基础上,加入节点 65:
在这里插入图片描述
插入节点 65 后进行如下步骤:
在这里插入图片描述
这个时候,你会发现对于节点 64 不管是红色节点仍是黑色节点,都会违反规则 5,路径中的黑色节点始终没法达成一致,这个时候仅经过【变色】已经没法达成目的。
咱们须要经过旋转操做,固然【旋转】操做通常还须要搭配【变色】操做。旋转包括【左旋】和【右旋】。
左旋:逆时针旋转两个节点,让一个节点被其右子节点取代,而该节点成为右子节点的左子节点。
左旋操做步骤以下:首先断开节点 PL 与右子节点 G 的关系,同时将其右子节点的引用指向节点 C2;而后断开节点 G 与左子节点 C2 的关系,同时将 G 的左子节点的应用指向节点 PL。
在这里插入图片描述
右旋:顺时针旋转两个节点,让一个节点被其左子节点取代,而该节点成为左子节点的右子节点。
右旋操做步骤以下:首先断开节点 G 与左子节点 PL 的关系,同时将其左子节点的引用指向节点 C2;而后断开节点 PL 与右子节点 C2 的关系,同时将 PL 的右子节点的应用指向节点 G。
没法经过变色而进行旋转的场景分为如下四种:
这种状况下,父节点和插入的节点都是左节点,以下图(旋转原始图1)这种状况下,咱们要插入节点 65。
规则以下:以祖父节点【右旋】,搭配【变色】。
在这里插入图片描述
按照规则,步骤以下:
在这里插入图片描述
这种状况下,父节点是左节点,插入的节点是右节点,在旋转原始图 1 中,咱们要插入节点 67。
规则以下:先父节点【左旋】,而后祖父节点【右旋】,搭配【变色】。
按照规则,步骤以下:
在这里插入图片描述
这种状况下,父节点是右节点,插入的节点是左节点,以下图(旋转原始图 2)这种状况,咱们要插入节点 68。
规则以下:先父节点【右旋】,而后祖父节点【左旋】,搭配【变色】。
在这里插入图片描述
按照规则,步骤以下:
在这里插入图片描述
这种状况下,父节点和插入的节点都是右节点,在旋转原始图 2 中,咱们要插入节点 70。
规则以下:以祖父节点【左旋】,搭配【变色】。
按照规则,步骤以下:
在这里插入图片描述
红黑树插入总结:
在这里插入图片描述
相比较于红黑树的节点插入,删除节点更为复杂,咱们从子节点是否为 null 和红色为思考维度来讨论。
当待删除的节点的子节点至少有一个为 null 节点时,删除了该节点后,将其有值的节点取代当前节点便可。
若都为 null,则将当前节点设置为 null,固然若是违反规则了,则按需调整,如【变色】以及【旋转】。
在这里插入图片描述
这种状况下,第一步:找到该节点的前驱或者后继。
前驱:左子树中值最大的节点(可得出其最多只有一个非 null 子节点,可能都为 null)。
后继:右子树中值最小的节点(可得出其最多只有一个非 null 子节点,可能都为 null)。
前驱和后继都是值最接近该节点值的节点,相似于该节点.prev=前驱,该节点.next=后继。
第二步:将前驱或者后继的值复制到该节点中,而后删掉前驱或者后继。
若是删除的是左节点,则将前驱的值复制到该节点中,而后删除前驱;若是删除的是右节点,则将后继的值复制到该节点中,而后删除后继。
这至关因而一种“取巧”的方法,咱们删除节点的目的是使该节点的值在红黑树上不存在。
所以专一于该目的,咱们并不关注删除节点时是否真是咱们想删除的那个节点,同时咱们也不需考虑树结构的变化,由于树的结构自己就会由于自动平衡机制而常常进行调整。
前面咱们已经说了,咱们要删除的其实是前驱或者后继,所以咱们就之前驱为主线来说解。
后继的学习可参考前驱,包括下面几种状况:
①前驱为黑色节点,而且有一个非 null 子节点
在这里插入图片描述
分析:由于要删除的是左节点 64,找到该节点的前驱 63;而后用前驱的值 63替换待删除节点的值 64,此时两个节点(待删除节点和前驱)的值都为 63;
删除前驱 63,此时成为上图过程当中间环节,但咱们发现其不符合红黑树规则 4,所以须要进行自动平衡调整。这里直接经过【变色】便可完成。
②前驱为黑色节点,同时子节点都为 null
在这里插入图片描述
分析:由于要删除的是左节点 64,找到该节点的前驱 63;而后用前驱的值 63 替换待删除节点的值 64,此时两个节点(待删除节点和前驱)的值都为 63。
删除前驱 63,此时成为上图过程当中间环节,但咱们发现其不符合红黑树规则 5,所以须要进行自动平衡调整。这里直接经过【变色】便可完成。
③前驱为红色节点,同时子节点都为 null
在这里插入图片描述
分析:由于要删除的是左节点 64,找到该节点的前驱 63;而后用前驱的值 63替换待删除节点的值 64,此时两个节点(待删除节点和前驱)的值都为 63;删除前驱 63,树的结构并无打破规则。
红黑树删除的状况比较多,但也就存在如下状况:
本文主要介绍了红黑树的相关原理,首先红黑树的基础二叉搜索树,咱们先简单说了一下二叉搜索树,而且讲了一下搜索的流程。
而后就针对红黑树的六大规则特色,红黑树的插入操做,删除操做,都使用了大量的图形来加以说明。
技术都是练出来的,有时候不少似是而非的地方,当动笔去写的时候,其实很好理解。
红黑树的使用很是普遍,如 TreeMap 和 TreeSet 都是基于红黑树实现的,而 JDK8 中 HashMap 当链表长度大于 8 时也会转化为红黑树。
更多资源和教程请关注公众号:非科班的科班。
若是以为我写的还能够请给个赞,谢谢你们,你的鼓励是我创做的动力