红黑树(一)——基本概念
1. 红黑树基本特性
1.1 红黑树定义
红黑树是一种特殊的二叉树,且必须要满足以下几个特性:
1. 每个节点或是黑色或是红色
2. 根节点是黑色
3. 每个叶节点是黑色(叶节点为空节点)
4. 如果一个节点是红色,则它的子节点必须是黑色
5. 从一个节点到该节点的所有叶节点的路径包含相同数目的黑色节点
1.2 红黑树时间复杂度
定理:红黑树的时间复杂度为 。
定义:
1. 为以节点 为根节点的子树的高度。
2. 为从节点 到其子树叶节点路径中黑色节点的数量。
根据特性5可知, 是唯一值。
又根据特性4可知,从一个节点到其叶节点路径上的黑色节点数目 路径上的红色节点数目。也就是说
引理:以 为根节点的红黑树,至少有 个内部节点。
使用数学归纳法证明引理:
(1) 当树的高度 时,
内部节点个数为 , ,则 ,显然满足 。
(2) 当 ,且当 时,包含的内部节点数至少为 ,
那么对于根节点 ,其左子树的内部节点个数至少为 ,
其右子节点的内部节点个数至少为 ,
则高度为 ,内部节点个数至少为 。
引理得证。
根据引理可以得出,一个节点数为 的红黑树, 。
又因为 ,可得, 。 (结论1)
红黑树是一种特殊的二叉树,对于有 个节点的二叉树而言,当其为满二叉树时,树的高度最小。
满二叉树的节点数量与高度的关系为 。
那么可以得出, 。(结论2)
由结论1和结论2可知, 。
所以,红黑树的时间复杂度为:
1.3 节点结构定义
红黑树的节点结构与一般的二叉树类似,但是多了一个标记颜色的变量。
class RBTreeNode<K, T> {
K key; // 键值,用于索引,可比较类型或是有相应的比较器
T value; // 存储的数据
ColorType color; // 节点颜色
RBTreeNode parent; // 父节点
RBTreeNode left; // 左子节点
RBTreeNode right; // 右子节点
}
enum ColorType {
BLACK,
RED,
}
2. 红黑树旋转操作
红黑树的旋转操作目的是在插入或删除节点后,尽可能的保持红黑树的特性。旋转操作分为左旋和右旋。
2.1 左旋操作
左旋操作效果如图所示。左旋操作会使当前节点与其右子节点位置互换。
对上图X
节点进行左旋,具体的操作主要分为三步:
RBTreeNode Y = X.right;
// 第一步:X节点与其右子节点的左子节点(即b节点)进行连接
X.right = Y.left;
if (Y.left != null) {
Y.left.parent = X;
}
// 第二步:X节点的父节点与右子节点(即Y节点)进行连接
Y.parent = X.parent;
if (X.parent != null) {
if (X == X.parent.left) {
X.parent.left = Y;
} else {
X.parent.right = Y;
}
}
// 第三步:X节点与Y节点父子关系互换
X.parent = Y;
Y.left = X;
2.2 右旋操作
右旋操作效果如图所示。右旋操作会使当前节点与其左子节点位置互换。
对上图X
节点进行右旋,具体的操作主要分三步:
RBTreeNode Y = x.left;
第一步:X节点与其左子节点的右子节点(即b节点)进行连接
X.left = Y.right;
if (Y.right != null) {
Y.right.parent = X;
}
第二步:X节点的父节点与左子节点(即Y节点)进行连接
Y.parent = X.parent;
if (X.parent != null) {
if (X == X.parent.left) {
X.parent.left = Y;
} else {
X.parent.right = Y;
}
}
第三步:X节点与Y节点父子关系互换
X.parent = Y;
Y.right = X;
3.总结
本篇文章主要介绍了红黑树的基本概念,包括红黑树的定义、时间复杂度及其证明、节点定义和旋转操作。
《数据结构与算法:红黑树(二)——数据操作》将介绍红黑树的数据操作。