红黑树
红黑树
说明
对自己所理解的红黑树的小小总结,仅此而已。
预备知识
- 二叉搜索树(BST)
- 2-3查找树(或2-3-4树)
定义
红黑树是含有红黑链接并满足下列条件的二叉查找树:
- 红链接均为左链接;
- 没有任何一个结点同时和两条红链接相连;
- 该树是完美黑色平衡的,即任意空链接到根结点的路径上的黑链接数量相同。
满足这样定义的红黑树和相应的2-3树是一一对应的。其中,红链接将两个2-结点连接起来构成一个3-结点,黑链接则是2-3树中的普通链接。
颜色表示
只需要在BST的基础上再添加一个属性。
private final static boolean RED = true;
private final static boolean BLACK = false;
private class Node{
Key key;
Value val;
Node left, right;
boolean color;
/* constructor */
}
private boolean isRed(Node x){
if (x == null) return false;
return x.color == RED;
}
旋转
-
左旋转:将红色的右链接转化为左链接
-
右旋转:将红色的左链接转化为右链接
-
无论左旋转还是右旋转,旋转操作都会返回一条链接。我们总是会用rotateLeft()或rotateRight()的返回值重置父结点(或根结点)中相应的链接。这可能会产生两条连续的红链接,但算法会继续用旋转操作修正这种情况。
-
颜色转换:我们用一个方法flipColors()来转换一个结点的两个红色子结点的颜色。除了将子结点的颜色由红变黑之外,同时还要将父节点的颜色由黑变红。(参照2-3树,将其过程对应起来)
插入
情况汇总
实现
因为保持树的平衡性所需的操作是由下到上在每个所经过的结点中进行的,所以只需要在递归调用之后完成这些旋转、重置颜色的操作。这些操作都可以通过一个检测两个结点的颜色的if语句完成。
private Node put(Key key, Value val, Node h){
if (h == null)
return new Node(key, val, RED, 1);
int cmp = key.compareTo(h.key);
if (cmp < 0) h.left = put(key, val, h.left);
else if (cmp > 0) h.right = put(key, val, h.right);
else h.val = val;
if (isRed(h.right) && !isRed(h.left)) h = rotateLeft(h);
if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h);
if (isRed(h.left) && isRed(h.right)) flipColors(h);
h.size = 1 + size(h.left) + size(h.right);
return h;
}
其中,第一条if语句会将任意含有右链接的3-结点(或临时的4-结点)向左旋转;第二条if语句会将临时的4-结点中两条连续红链接中的上层链接向右旋转;第三条if语句会进行颜色转换并将红链接在树中向上传递。
性能
- 一棵大小为N的红黑树的高度不会超过2lgN。
- 一棵大小为N的红黑树中,根结点到任意结点的平均路径长度为~1.00lgN。