[数据结构]红黑树
1.概念
发展历程
- 线性查找-性能低
- 二分查找-可能退化成链表
- AVL-变化频繁,需要经常更新
- 引入红黑树结构
定义
引入带颜色的节点也是为了方便在进行插入或删除操作时,如果破坏了二叉查找树的平衡性能通过一系列变换保持平衡。
红黑树的查找、插入、删除的时间复杂度均为O(log2n)
(注意:AVL的查找、插入、删除的时间复杂度均为O(log2n)
性质
-
结点是红色或黑色;
-
根结点是黑色。
-
叶子结点(也叫外部结点、NULL结点、失败结点)是黑色。
-
不存在两个相邻的红结点。(即红结点的父结点和子结点都是黑色的)
-
从任意结点到可达的叶子结点的每个路径包含相同数目的黑色节点。
结论
-
从根到叶节点的最长路径不大于最短路径的2倍。
-
有n个内部节点的红黑树的高度h ≤ log2(n+1)。
节点定义的代码
// 红黑树的结点定义
struct RBnode{
int key; // 关键字的值
RBnode *parent; // 父节点的指针
RBnode *lChild; // 左孩子的指针
RBnoce *rChild; // 右孩子的指针
int color; // 结点颜色,如可用 0/1 表示 黑/红。也可用枚举型 enum 表示颜色。
}
2.红黑树的插入
先查找,确定插入位置(同二叉排序树),插入新结点
- 新结点为根——染为黑色
- 新结点非根——染为红色
- 若插入新结点后依然满足红黑树定义,则插入结束
- 若插入新结点后不满足红黑树定义,需要调整,使其重新满足红黑树定义
- 黑叔:旋转加染色
- LL型:右单旋,父换爷+染色
- RR型:左单旋,父换爷+染色
- LR型:左、右双旋,儿换爷+染色
- RL型:右、左双旋,儿换爷+染色
- 红叔:染色+变新
- 父叔爷染色,爷变为新结点
- 黑叔:旋转加染色
红黑树插入动画演示:http://rbtree.phpisfuture.com/
3.红黑树的删除
红黑树的插入操作容易导致连续的两个红结点,破坏性质4,而删除操作容易造成子树黑高的变化(删除黑节点),破坏性质5。
删除一个节点的两种情况:
- 待删除节点没有孩子
- 待删除节点只有右子树或左子树
详细情况讨论参考:
王道考研2023 280页
https://segmentfault.com/a/1190000022278733