紅黑樹
紅黑樹定義
- 紅色結點均爲左節點 – 紅色結點與黑色結點合併會得到一個-3結點
- 沒有任何一個結點同時和兩個紅色結點相連
- 任一空連接到根節點的長度和黑色結點的數目相同
結點定義
// 紅色結點記爲true,黑色記爲false
private static final boolean RED = true;
private static final boolean BLACK = false;
// BST helper node data type
private class Node {
private Key key; // key
private Value val; // associated data
private Node left, right; // links to left and right subtrees
private boolean color; // color of parent link
private int size; // subtree count
public Node(Key key, Value val, boolean color, int size) {
this.key = key;
this.val = val;
this.color = color;
this.size = size;
}
}
紅黑樹的左旋與右旋,以及顏色變換:
private Node rotateLeft(Node h) {
Node x = h.right;
x.left = h;
x.color = h.color;
// 與父節點鏈接變爲紅色
h.color = RED;
x.size = size(h.left) + size(h.right) + 1;
return x;
}
private Node rotateRight(Node h) {
Node x = h.left;
h.left = x.right;
x.right = h;
x.color = h.color;
h.color = RED;
x.size = size(h.left) + size(h.right) + 1;
return x;
}
private void flipColors(Node h) {
if (h == null) return;
h.color = RED;
h.left.color = BLACK;
h.right.color = BLACK;
}
紅黑樹插入算法的關鍵:
- 要在一個3-結點下面插入一個新節點,需要將結點臨時轉換成一個4-結點
- 將其分解並將紅鏈接由中間鍵傳遞給父節點
- 直到遇見一個2-結點或根節點
private void put(Key key, Value val) {
root = put(root, key, val);
root.color = BLACK;
}
private Node put(Node h, Key key, Value val) {
// 如果沒有則插入一個紅色結點,這樣方便以後調整
if (h == null)
return new Node(key, val, RED, 1);
int cmp = key.compareTo(h.key);
// 滿足BST的性質,如果小於,則從左邊插入
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;
/**
* 紅黑樹調整的目的是爲了在插入結點的同時動態調整樹的高度
* 避免樹的高度過高,提升索引的效率
*/
// 重點!! 紅黑樹的調整過程
// 左黑右紅
if (!isRed(h.left) && isRed(h.right))
h = rotateLeft(h); // 左旋
// 左紅右黑
if (isRed(h.left) && !isRed(h.right))
h = rotateRight(h); // 右旋
// 全紅
if (isRed(h.left) && isRed(h.right))
flipColors(h); // 顏色反轉 -- 結點成爲2-結點,父節點成爲3-結點
// 調整樹的規模
h.size = size(h.left) + size(h.right) + 1;
return h;
}
刪除算法之後補充