前言
红黑树和2-3树
是等价的,所以首先得理解2-3树
。
两个问题
-
2-3树
是啥?- 满足二分搜索树的基本性质
- 节点可以存放一个或两个元素,可以有两个或三个孩子
2-3树
是一种绝对平衡的树,意味着从根节点到任意一个叶子节点所经过的节点数是相同的。
-
为什么说
红黑树
和2-3树
是等价的?
定义
- 每个节点非黑即红
- 根节点为黑
- 每一个叶子节点(最后的空节点)是黑色的
- 如果一个节点是红色的,那么他的孩子节点都是黑色的
- 从任意一个节点到叶子节点,经过的黑色节点是一样的(所谓的黑平衡)
复杂度
严格意义上,红黑树不是平衡二叉树,它的最大高度趋近于 2 l o g 2 n 2log_2{n} 2log2n,但是由于 2 2 2是一个常数,所以它的复杂度仍然表示为 O ( l o g 2 n ) O(log_2{n}) O(log2n)
应用
Java
中TreeMap
的实现,是一种字典结构,也就是所谓的关联数组。
实现
节点
与AVL
不同,红黑树的平衡因子通过颜色来维护,而不是高度,因此其成员变量中需要一个color
,初始化默认为红色:
private static final Boolean RED = true;
private static final Boolean BLACK = false;
public Node(K key, V value) {
this.key = key;
this.value = value;
this.color = RED;
}
旋转
与AVL
相同,红黑树
也是通过树的旋转来维护平衡,只是维护的实际过程稍有差别。
左旋
// node x
// / \ 左旋转 / \
// T1 x ---------> node T3
// / \ / \
// T2 T3 T1 T2
public Node<K, V> leftRotate() {
Node<K, V> x = right;
right = x.left;
x.left = this;
x.color = color;
color = RED;
return x;
}
右旋
与左旋相反
颜色翻转
// 左右子树颜色均为红色才会出现翻转,因此不存在为空状况,此方法不影响树的高度
private void flipColor() {
this.color = RED;
this.left.color = this.right.color = BLACK;
}
时机
与AVL
不同,红黑树的旋转条件不是互斥而是并列的,也就是说需要依次判断是否需要旋转或颜色翻转,考虑如下情况:
/**
* 保持(黑)平衡并翻转颜色
*
* @return
*/
public Node<K, V> refresh() {
Node<K, V> self = this;
// 左子树为红,表示不为空,无需判空
if (isRed(self.left) && isRed(self.left.left)) {
self = self.rightRotate();
}
if (!isRed(self.left) && isRed(self.right)) {
self = self.leftRotate();
}
if (isRed(self.left) && isRed(self.right)) {
self.flipColor();
}
return self;
}