完全参考《Algorithm》edition IV中的相应章节
通过求树的高度来实现对implementation的测试
2-3树是一种平衡树,通过自下而上地添加一条数据,往上调整来实现树的平衡,而红黑树就是2-3树的一种实现(把red edge放平就是一棵平衡的2-3树),在红黑树中从根节点到叶子节点的距离计算的是黑色的edge,以此为了维持平衡,在修正红黑树的前后要保证不影响各个支路平衡性
1. 为什么23树能比较平衡呢:每次插入都尽量组成3node树,即保留树的高度不变;然后对红黑树做一些限制(红edge不能连续出现,任意节点的黑色edge数加起来一样),所以一边最多比另外一边多一倍的深度
2. 23树,红黑树是完全平衡的二叉树吗:不是,23树其实只是看起来高度一样,但是3个node的比较了2次;红黑树查找是红色黑色是忽略的
3种基本操作:
(1)
(2)
(3)
可能有4种需要修改的情况出现,各种情况都对应到23树的insert
实现:
/*
* 在这里用的是红黑树实现Map,Set也是一样的
* test case: insert 2 的幂次个数,最后书的高度应该是logN
*/
public class RedBlackTree<Key extends Comparable<Key>, Value> {
private static final boolean RED = true;
private static final boolean BLACK = false;
private Node root;
private class Node {
Key key;
Value val;
Node left, right;
boolean color; // 定义为进入该node的edge是不是红色edge
private Node(Key key, Value val, boolean color) {
this.key = key;
this.val = val;
this.color = color;
}
}
private boolean isRed(Node x) {
if(x == null) return false; // null links are black, because red means merge to top
return x.color == RED;
}
/*
* 有3种情况需要处理
* 1. rotate left
* 2. rotate right (暂时的)
* 3. flip color
* 3个函数入参是最顶端的node, 返回的也都是最顶端的node,这一点在insert的时候很重要
*/
// 1. rotate left
private Node rotateLeft(Node h) {
Node x = h.right;
h.right = x.left;
x.left = h;
x.color = h.color;
h.color = RED;
return x;
}
// 2. rotate right
private Node rotateRight(Node h) {
Node x = h.left;
h.left = x.right;
x.right = h;
x.color = h.color;
h.color = RED;
return x;
}
// 3. flip color
private void flipColor(Node h) {
h.color = RED;
h.left.color = BLACK;
h.right.color = BLACK;
}
/*
* 实现API:put, find
*/
// put
public void put(Key key, Value val) {
root = put(root, key, val);
}
private Node put(Node h, Key key, Value val) {
if(h == null) return new Node(key, val, RED);
int cmp = key.compareTo(h.key);
if(cmp < 0) h.left = put(h.left, key, val);
else if(cmp > 0) h.right = put(h.right, key, val);
else h.val = val;
/*
* 按照顺序判断是不是需要调整,有可能三者都会执行到,而且往回递归的时候还要check这3项
* 因为3种情况都有可能执行,所以修正时返回最顶端的元素很重要
* 其实就是按照最复杂的那个调整情况来
*/
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)) flipColor(h);
return h; // h可能调整过了,所以要返回
}
// height, only for test
public int height() {
return height(root);
}
private int height(Node h) {
if(h == null) return 0;
return 1 + Math.max(height(h.left), height(h.right));
}
}
测试:
public class Test {
public static void main(String[] args) {
RedBlackTree<Integer, Integer> tree = new RedBlackTree<Integer, Integer>();
for(int i=0; i<=256; i++)
tree.put(i, i);
System.out.println(tree.height()); // assert to be 9
for(int i=512; i>=257; i--)
tree.put(i, i);
System.out.println(tree.height()); // assert to be 10
}
}