红黑树(Red Black Tree)
- 红黑树也是一种自平衡的二叉搜索树
- 也可称为平衡二叉B树 红黑树必须满足以下五条性质:
- 节点是
Red或者Black - 根节点是
Black - 叶子节点(外部节点、空节点)都是
Black Red节点的子节点都是Black
Red节点的Parent都是Black- 从根节点到叶子节点的所有路径上不可能有2个连续的
Red节点
- 从任意节点到叶子节点的所有路径都包含相同数目的
Black节点
红黑树的等价变换
红黑树和4阶B树具有等价性(2-3树即3阶B树不能完美匹配红黑树的所有情况)Black节点和它的Red子节点融合在一起,形成一个B树节点红黑树的Black节点个数和4阶B树的节点总个数相等
红黑树对比4阶B树
添加
4阶B树所有节点的元素个数都满足[1,3]- B树中,新添加的元素一定是添加到叶子节点中
- 建议新添加的节点默认为
Red,这样能快速满足红黑树的性质(满足1、2、3、5,第4条不一定) - 如果添加的是根节点,染成
Black即可
例如在下图中的红黑树中添加元素
由于添加元素都发生在叶子节点中,并且红黑树和4阶B树具有等价性,那么上图便可以涵盖所有的添加情况,分别为节点17的左右子树、节点33的左右子树、节点46的左子树、节点50的左右子树、节点72的左右子树、节点76的右子树、节点88的左右子树,共计12种添加情况。
这12种情况中可以看出如果是添加节点的父节点是Black的话,因为添加元素是Red,添加后并不影响红黑树的特性,这时并不需要进行调整,但是如果父节点是Red那么就会出现双红的局面,添加过后一定要进行调整,那么这里先可以将12种情况分为两大类添加后依然满足红黑树特性和添加后不满足红黑树特性。
添加后依然满足红黑树特性
有四种情况满足红黑树特性:parent是Black
添加后不满足红黑树特性
有八种情况不满足红黑树的性质4:Parent为Red(双红)
同时这八种情况中又可以分为添加后不上溢和上溢的情况,先来讨论不上溢的情况,不上溢有四种情况,同时又可以把不上溢的四种情况根据类比AVL树中的情况分为LL、RR、LR、RL。
不上溢
LL\RR
同样可以类比AVL树中的情况,可以看出这里是LL及RR的情况。
判定条件:叔父节点不是Red
处理:
parent染成Black,grand染成Redgrand进行单旋操作(LL右旋转,RR左旋转)
操作后如图所示
LR\RL
同样判定条件是:叔父节点不是Red
处理:
1.自己染成Black,grand染成Red
2.如果是LR,parent左旋转,grand右旋转
3.如果是RL,parent右旋转,grand左旋转
处理之后如下图所示
上溢
上溢的情况共有四种,同样可以区分为LL、LR、RL、RR,并且如图所示,这四种方式的处理是同样的方式来处理。
判定条件:叔父节点是Red
处理:
1.parent和uncle染成Black
2.grand染成Red向上合并(当做是新添加的节点)
3.grand向上合并时可能会再次发生上溢,若上溢持续到根节点,只需将根节点染成Black
接下来就按照LL、LR、RL、RR四种不同的情况来分别看看添加后的情况
上溢-LL
上溢-RR
上溢-LR
上溢-RL
以上就是添加的12种情况也是所有情况的总结,下面用代码来实现
添加的代码实现
删除
删除的情况会比添加复杂一些,首先再来明确一下红黑树等价于4阶B树,而且真正被删除的元素一定是在叶子节点中,而且等价于4阶B树,那么删除的节点一定是以下情况中的一种
大体来看先分为:删除红色节点和删除黑色节点两个大情况来讨论
删除红色节点
由图可知,删除红色节点后依然保持红黑树所有特征,因此不用任何调整,所以直接删除即可
删除黑色节点
由图可以分为三种情况:
- 有2个红色子节点的黑节点,这种情况可以不予考虑,因为它不可能直接被删除,而是找它的子节点删除
- 有1个红色子节点的黑节点,红色节点可能在左边可能在右边
- 黑色叶子节点
接下来对于这三种情况进行讨论
删除有一个红色子节点的黑色节点
判定条件: 用以替代的子节点是红色
处理: 把替代的红色子节点染成黑色就可以保持红黑树的性质
删除黑色叶子节点
在删除黑色叶子节点这种情况中,情况又会根据删除的黑色叶子节点的兄弟节点是红色还是黑色来划分,因为从B树的角度来看,删除叶子节点时会发生下溢,同时下溢会根据兄弟节点能不能借来分开讨论,但是红黑树这里又和B树的删除情况还不太一样,就是因为兄弟节点是否同在最后一层,这种情况便可以根据兄弟节点的颜色来进行判定,接下来会详细描述。
删除黑色叶子节点-兄弟节点是黑色
删除黑色叶子节点-兄弟节点是黑色-有至少一个红色子节点
这里先讨论兄弟节点可以出借的情况,一共分为下面三种
现在从左至右分别来说明处理过程:
-
删除
88的黑色子节点会导致下溢,同时从兄弟节点76中可以出借节点88,这里首先要对76节点进行左左旋转,78节点上去之后情况便转化为第二种情况一样了,同为LL的情况。 -
删除
88的黑色子节点会导致下溢,同时从兄弟节点76中可以出借节点72,这里情况比较简单,直接对80节点右旋转后,76成为子树的根节点,72和80成为子节点,但是此时需要对76继承80原来的颜色,72和80要染成黑色。 -
这种情况跟第二种分析的一样,唯一不同的是在
80进行右旋转后,76原来的右节点78会成为80的左节点,并且颜色不变,依然为红色。
这里附上第一种情况转换一次的中间过程(此处暂未对颜色进行处理,故这时并不是红黑树的状态)
下图就是处理后的情况
总结:
这种情况的判定条件是:兄弟节点至少有一个红色子节点
处理过程:
- 进行相应的旋转操作
- 旋转后的中心节点要继承原来子树根节点的颜色
- 旋转后左右子节点染为黑色
删除黑色叶子节点-兄弟节点是黑色-没有红色子节点
在删除黑色叶子节点、兄弟节点是黑色并且没有红色子节点这种情况的时候,还会根据被删除黑色子节点的父节点颜色为红色还是黑色来进行划分
分类讨论:
Parent是红色节点Parent是黑色节点
先来讨论Parent是红色节点的情况,如图
删除88节点后产生下溢,节点80会和76组成一个新的节点,80颜色变黑,76变黑,结果为下图
总结:
判定条件:兄弟节点没有红色子节点,并且被删除的黑色子节点的父节点是红色
处理:
- 将
兄弟节点染红,父节点染黑,即可修复红黑树性质
Parent是红色节点的情况已经讨论完成,现在来看Parent是黑色节点的情况
兄弟节点没有红色子节点,并且被删除的黑色子节点的父节点是黑色- 会导致
parent也发生下溢 - 这时只需要把
parent也当做是被删除的节点来处理即可
删除黑色叶子节点-兄弟节点是红色
在这种情况下要删除
88,因为此时它的兄弟节点是55,但是根据B树的角度来看兄弟节点并不和它在一层,这时是没有办法借的,现在就是要想办法把88的兄弟节点弄到一层里,此时对80节点进行右旋转即可变为下图
这时的情况再次变为了刚讨论的兄弟节点是黑色的那种
总结:
判定条件:如果兄弟节点是红色
处理方法:
兄弟节点染成黑色,父节点染成红色父节点进行右旋转
删除代码实现
红黑树 VS AVL树 总结
再来回顾一下红黑树的五条性质:
- 节点是
Red或者Black - 根节点是
Black - 叶子节点(外部节点、空节点)都是
Black Red节点的子节点都是Black
Red节点的Parent都是Black- 从根节点到叶子节点的所有路径上不可能有2个连续的
Red节点
- 从任意节点到叶子节点的所有路径都包含相同数目的
Black节点
只要满足这5条性质就可以保证红黑树等价于4阶B树
对于红黑树来说:
- 相比于
AVL树,红黑树的平衡标准比较宽松:没有一条路径会大于其他路径的2倍 红黑树的平衡是一种弱平衡红黑树的最大高度是,这依然是O(logn)的级别
AVL树总结:
- 平衡标准比较严格:每个左右子树的高度差不超过1
- 最大高度为(100W个节点,
AVL树最大树高28) AVL树的平均时间复杂度:- 搜索:
O(logn) - 添加:
O(logn)以及O(1)次的旋转 - 删除:
O(logn)最多需要O(logn)次的旋转
- 搜索:
- 搜索、添加、删除都是
O(logn)复杂度,其中添加仅需O(1)次旋转调整、删除最多需要O(logn)次旋转调整
红黑树总结:
- 平衡标准比较宽松:没有一条路径会大于其他路径的2倍
- 最大高度为(100W个节点,
红黑树最大树高40) 红黑树的平均时间复杂度:- 搜索:
O(logn) - 添加:
O(logn)以及O(1)次的旋转 - 删除:
O(logn)以及O(1)次的旋转
- 搜索:
- 搜索、添加、删除都是
O(logn)复杂度,其中添加、删除都仅需O(1)次旋转调整
选择使用AVL树还是红黑树的参考:
- 搜索的次数远远大于插入和删除,选择
AVL树;搜索、插入、删除次数几乎差不多,选择红黑树 - 相对于
AVL树来说,红黑树牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体来说性能要优于AVL树 红黑树的平均统计性能优于AVL树,实际应用中更多选择使用红黑树