12.红黑树
邂逅 红黑树
首先,红黑树很难,难到什么程度呢?
首先你跟别人聊数据结构的时候,他不会和你聊红黑树,因为它是数据结构中一个难点中的难点
数据结构的学习本来就比较难了,红黑树是又将难度上升一个档次的知识点
面试的时候经常出现这个场景:
面试管:你知道红黑树吗?
面试者:知道啦
面试管:知道原理吗?
面试者:不知道啊
面试官:那你让“不”过来面试我们公司吧,
你先回去等通知吧
哪些面试会出现红黑树呢?
通常在比较知名的互联网公司面试会出现红黑树的题目
因为它可以作为你对数据结构掌握深度的很好考虑点
但是在除去大型互联网公司之外,几乎不会考虑到红黑树
因为面试管很有可能自己都不懂
OK,在这里,我们就一起来踏入数据结构红黑树这块禁区
红黑树的规则
红黑树,除了符合二叉搜索树的基本规则外,还添加了一下:
节点是红色或黑色
根节点是黑色
每个叶子节点都是黑色的空节点(NIL节点)
每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个链接的红色节点)
从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点
这些规则会让人一头雾水
完成搞不懂规则叠加起来,怎么让一棵树平衡的
但是它们还是被一些聪明的人发明出来了
到底是怎么平衡的呢?
红黑树的相对平衡
前面的约束,确保了红黑树的关键特性:
从根到叶子的最长可能路径,不能超过最短可能路径的两倍长
结果就是这个树基本是平衡
虽然没有做到绝对的平衡,但是可以保证在最坏的情况下,依然是高效的
为什么可以做到最长路径不超过最短路径的两倍呢?
性质4决定了路径不能有两个相连的红色节点
最短的可能路径都是黑色节点
最长的可能路径是红色和黑色交替
性质5所有路径都有相同数目的黑色节点
这就表明了没有路径能多余任何其他路径的两倍长
变色
插入一个新节点时,有可能树不再平衡,可以通过三种方式的变换,让树保持平衡
换色-左旋转-右旋转
变色:
为了重新符合红黑树的规则,尝试把红色节点变为黑色,或者把黑色节点变为红色
首先,需要知道插入的新的节点通常都是红色节点
因为在插入节点为红色的时候,有可能插入一次是不违反红黑树任何规则的
而插入黑色节点,必然会导致有一条路径上多了黑色节点,这是很难调整的
红色节点可能导致出现红红相连的情况,但是这种情况可以通过颜色调换和旋转来调整
旋转
左旋转
逆时针旋转红黑树的两个节点,使得父节点被自己右孩子取代,而自己称为自己的左孩子、
图中,身为右孩子的Y取代了X的位置,而X变成了Y的左孩子。此为左旋转
问题:如果它们有子树是否会影响旋转?
右旋转
顺时针旋转红黑树的两个节点,使得父节点被自己左孩子取代,而自己称为自己的右孩子
图中,身为左孩子的Y取代了X的位置,而X变成了Y的右孩子。
问题:如果它们右子树是否影响旋转呢?
插入操作
接下来,讨论一下插入的情况:
设要插入的节点为N,其父节点为P
其祖父节点为G,其父亲的兄弟节点为U(即P和U是同一个节点的子节点)
情况一:
新节点N位于树的根上,没有父节点
这种情况下,我们直接将红色变换成黑色即可,这样满足性质2
情况二:
新节点的父节点P是黑色
性质4没有失效(新节点是红色的),性质5也没有任何问题
尽管新节点N有两个黑色的叶子节点nil,但是新节点N是红色的,所以通过它的路径中黑色节点的个数依然相同,满足性质5
情况三:
情况三:
P为红色,U也是红色
操作方案:
将P和U变换为黑色,并且将G变换为红色
现在新节点N有了一个黑色的父节点P,所以每条路径上黑色节点的数目没有改变
而从更高的路径上,必须都会经过G节点,所以那些路径的黑色节点数目也是不变的,符合性质5、
可能出现的问题:
但是,N的祖父节点G的父节点也可能是红色,这就违反了性质3没可以递归的调整颜色
但是如果递归调整颜色到了根节点,就需要进行旋转了,待会儿我们的例子中会遇到这个问题
情况四:
情况四:
N的叔叔U是黑节点,且N是左孩子
操作方案:
对祖父节点G进行依次右旋转
在旋转查收的树中,以前的父节点P现在是新节点已经以前父节点G的父节点
交换以前的父节点P和祖父节点G的颜色(P为黑色,G变成红色 - G原来一定是黑色,为什么?)
B节点向右平移,称为G节点的左子节点
情况五:
情况五:
N的叔叔U是黑色节点,且N是右孩子
操作方案:
对P节点进行依次左旋转,形成情况四的结果
对祖父节点G进行一次右旋转,并且改变颜色即可
红黑树案例
案例:一次插入10到1
插入10
插入节点10
将节点10的颜色改为黑色
插入9
符合情况2
不需要任何变化
插入8
情况4
插入7
符合情况3
原来:父红叔黑祖黑 -> 父黑叔黑祖红
问题:不符合规则2
插入6
情况4
父变成黑色
祖父变成红色
进行右旋转
插入5
符合情况3
6节点变成黑色
8节点变成黑色
7节点变成红色
插入4
情况4
颜色变换:5节点变成黑色,6节点变成红色
旋转操作
插入3
第一次变化:符合情况3:4节点变成黑色,6节点变成黑色,5节点变成红色
第二次变化:符合情况4:7节点变成黑色,9节点变成红色,右旋转
插入2
3节点颜色变成黑色,4节点颜色变成红色
右旋转
插入1
第一次变化:2和4节点变成黑色,3节点变成红色
第二次变化:5和9节点变成黑色,7变成红色
删除&代码
红黑树的删除
我们已经学习过了二叉搜索树的删除操作,比较复杂
我们已经学习过了红黑树的插入规则,比较复杂
红黑树的删除操作呢?
它就需要将两个复杂的操作结合起来考虑,所以难度非常大
插入和删除的代码实现:
插入的步骤我们已经一步步的进行了分析
分析完成后,写出插入的代码并不是很难
删除也需要按照插入一样,分成很多种情况,然后写出最终的代码形式
目前,我们已经讲解了树的很多知识了,作为前端数据结构和算法的补充,就先到这里
有机会的时候,我们用其他语言来进一步了解红黑树的删除和代码,比如Java 比如python