红黑树是一种常用的平衡二叉树数据结构,搜索(search)、插入(insertion)和删除(deletion)的时间复杂度为O(Logn)。
用于C++实现Map/Set, Java实现TreeMap/HashMap等数据结构,此外还可以用于实时计算程序和函数式编程中。
【红黑树的性质】
- 根节点总为黑色。Root of tree is always black
- 不存在相邻的红色节点。There are no two adjacent red nodes
- 从任何一个节点出发到它的任何一个NULL叶节点的所有路径,经过的黑色节点数量之和相同。Every path from a node (including root) to any of its descendant NULL node has the same number of black nodes
Features
- 每个红黑树的高度: h ≤ 2Log2(n+1)
- 每个红黑树的黑色节点数: Nblack ≥ n / 2
- The height of a Red-Black tree is always O(Logn)
- 任何一个节点到叶节点的黑色节点数(Black Height): BH >= h/2.
- There is a root to leaf path with at-most Log2(n+1) black nodes
【红黑树的操作】
首先说明:我主要是总结操作实现的步骤,方便你更好的记忆,这里并没有放任何实现代码。
【插入操作】
- 进行平衡二叉树插入操作
- 修复插入节点可能出现的违规,根据插入节点的情况分类
- 插入节点没有根节点: 染黑插入节点
- 插入节点Parent为黑: 直接插入
- 插入节点Parent为红: 根据Uncle的情况分类
- Uncle是红色的: 染黑Uncle和Parent,染红GrandParent
- Uncle是黑色的:
- 三角型: 旋转Parent,执行直线型的操作
- 直线型: 旋转GrandParent,交换插入节点与GrandParent的颜色
【插入操作口诀】
我根我爸黑,那就很简单。
我爸要是红,伯伯也红,黑爸黑伯红祖父,伯伯若黑,三角转成直,直也转一次,转后祖父与兄色互换,全部结束根染黑。
【删除操作】
-
搜索删除节点
-
查找替换节点
-
删除节点是叶节点,替换节点为null
-
删除节点有一个子代,替换节点为该子代
-
删除节点有两个子代,替换节点为后继节点(successor)
-
执行删除节点,根据删除节点和替换节点的情况分类讨论
-
若删除节点有两个后代: 交换替换节点与删除节点键值,对替换节点进行删除操作
-
- 若删除节点无两个后代:
- 删除节点是树根: 直接删除或替换
- 删除节点是叶节点: 若删除节点是黑色,则为双黑,修复双黑
- 删除节点有一个后代: 若不是双黑情况,染黑替换节点
【删除操作口诀】
删除节点两后代,交换键值往下看。
删除节点是树根,直接删除或替换。
删除节点无后代,自己若黑修双黑。
删除节点有一子,若是红子染成黑。
【修复双黑操作】
什么是双黑和修复双黑?
双黑是指删除操作中替换节点与删除节点均为黑色的情况,双黑标记表明了当前树违背了黑色节点数目一致的原则,需要进行修复。修复双黑就是为了保证红黑树满足上述合法性的操作。
具体操作:
根据删除节点的兄弟节点情况进行分类讨论:
- 若不存在兄弟: 双黑要传递给父亲,对父亲进行修复双黑
- 兄弟是红色: 染红父亲,染黑兄弟,把兄弟转上去,转化为兄弟为黑的情况
- 兄弟是黑色,此时需要讨论兄弟儿子的情况
- 兄弟没有红色儿子,先染红兄弟,然后讨论父亲颜色的情况
- 父亲为红色: 染黑父亲即可
- 父亲为黑色: 对父亲节点修复双黑
- 兄弟有红色儿子,根据兄弟与兄弟儿子形成的结构进行分类讨论
- 直线型: 兄弟儿子染成黑色,兄弟染成父亲色,然后把兄弟转上去
- 三角型: 把兄弟儿子染成和父亲同色,把兄弟儿子转到兄弟的位置,再把兄弟的儿子转到父亲的位置
- 兄弟没有红色儿子,先染红兄弟,然后讨论父亲颜色的情况
写在最后
我在该文章中没有去说明实现步骤的原因和细节,因为这篇文章主要是为了提供实现操作记忆的口诀和动图,和记忆代码相比,这样更能方便记住,可以在面试笔试的时候再进行展开。
我还制作了一个关于红黑树的视频,欢迎各位观看:
https://www.bilibili.com/video/av45909616/
关于本人:我是一名工作经验两年多的前端,主要方向是数据可视化和工具开发,最近离职重新学习各种计算机基础,由于经验不足,可能会有不少错误之处,如能够指正将十分感激。