红黑树
概念
红黑树,又被称为对称二叉B树。
其本质是一种二叉查找树,单它在二叉查找树的基础上额外添加了一个标记(颜色),同时具有一定的规则。这些规则使红黑树保证了一种平衡,插入、删除。查找的最坏时间复杂度都为O(log n)
,它的统计性能好于平衡二叉树(AVL树)
特性
- 每个节点要么是红色,要么是黑色
- 根节点永远是黑色的
- 所有的叶节点都是是黑色的(注意这里说叶子节点其实是上图中的 NIL 节点)
- 每个红色节点的两个子节点一定都是黑色
- 从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点
黑色高度
从根节点到叶子节点的路径上,黑色节点的个数
红黑树的左旋右旋
红黑树的左旋右旋目的是调整红黑节点结构,转移黑色节点位置,使其在进行插入、删除后任能保持红黑树的5条性质
左旋
把右孩子变成自己的父节点,自己变成右孩子的左孩子,右孩子的左孩子变成自己的右孩子
右旋
即左旋反过来实现
红黑树的平衡插入
红黑树的节点插入主要分两步
- 首先和二叉查找树的插入一样
- 然后调整结构,保证满足红黑树状态
- 对节点进行重新填色
- 对树结构进行旋转
插入节点
就如二叉查找树一样先插入节点
插入后调整红黑树结构
插入的节点颜色可能有两种
- 插入的节点为黑色,那么一定会违背第五条特性
- 插入的节点是红色,当我们是在红色节点下插入红色节点,那么一定会违背第四条特性
综合上面的情况考虑,插入黑色是一定会违背特性的,那么插入的节点一定要是红色,此时只要关心父节点是否为红,如果是红的,就要把父节点进行变化,让父节点变成黑色,或者换一个黑色节点当父亲,这些操作的同时不能影响不同路径上的黑色节点数一致的规则
情况一:父节点和叔叔节点都是红色
最简单的方式是将父节点P
染黑,此时会违背特性四和特性五,那不如将父节点P
和叔叔节点U
一起变成黑色,然后将爷爷节点G
染红即可,因为两个孩子节点是黑色节点的父节点是红色节点,并且要满足特性五
但是如果爷爷节点G
的父节点也是红色的呢?那就得递归了
情况二:父节点为红色,叔叔节点是黑色
同样先考虑父节点P
变成黑色,此时违背特性五,也没有别的办法,只有考虑变化爷爷节点G
,但是如果单纯改父节点G
的颜色会不满足特性五,所以考虑将父节点P
右旋,这时把父节点P
变成黑的,多了一个黑节点,再把爷爷节点G
变成红的,就平衡了
上述情况都是插入的节点为左孩子
当插入节点是右孩子时
红黑树的平衡删除
红黑树的节点删除也分为两步
- 二叉查找树的删除
- 结构调整
二叉查找树的删除
情况一:要删除的节点正好是叶子节点
直接删除
情况二:有左孩子或者右孩子,仅拥有一个
直接把这个孩子上移放到要删除的位置
情况三:有两个孩子
就需要选一个合适的孩子节点作为新的根节点,该节点称为继承节点
删除后的结构调整
删除的节点颜色有两种可能
- 如果当前待删除节点是红色的,它被删除之后对当前树的特性不会造成任何破坏影响
- 如果被删除的节点是黑色的,这就需要进行进一步的调整来保证后续的树结构满足要求
所以只需要考虑删除节点是黑色的情况
情况三:
可以先将继承节点替换该节点,然后使用情况一或者情况二的后续解决办法即可
情况二:
满足情况二的节点一定是红色节点,可以直接删除,最简单
情况一:
此等情况相对复杂
情况一:待删除节点D的兄弟节点S为红色(以D为右节点为例)
将父节点和兄弟节点的颜色互换,然后将父节点左旋
情况二:兄弟节点是黑色,远侄子节点是红色(绿色可为任何颜色)
将父节点和兄弟节点的颜色对调,然后将父节点左旋,若近侄子节点为黑,必为NIL
节点
情况三:兄弟节点是黑色,近侄子节点是红色(绿色可为任何颜色)
将兄弟节点右旋,然后将父节点左旋,再将近侄子节点和父节点交换颜色,并把父节点置为黑
情况四:兄弟节点是黑色,且为叶子节点
直接将兄弟节点设置为红色