RedBlackTree 紅黑樹
文章目錄
1、2-3 樹
紅黑樹和2-3書有着等價的關係。我們瞭解了紅黑樹之前,必須先了解2-3這種數據結構。
1.1、2-3 樹的基本結構
2-3 樹也滿足樹的基本結構。但是一個節點可以存儲一個或者兩個元素。每一個節點可以有兩個或者三個孩子。
下面是一種2-3樹的結構。排序的方式是根據字符的大小
。
我們可以根據上面的結構來驗證2-3樹是否滿足樹的基本結構。
A->E->F->G->H->K->M->N->R->S->Z
可以對樹結構進行中序遍歷來查看該結構是否具有順序性。我們可以得出一個結論就是:
可以看得出來任意節點的孩子節點的高度是相同的。下面就開始介紹這種數據結構是如何維持平衡性的。
1.2、2-3樹添加元素
通過介紹如何添加元素來介紹這種樹結構是如何維持平衡性的。
下面以實例進行講解,這個地方主要還是靠大家的看。
添加的順序是:S->E->A->R->C->H->X->M->P
最關鍵的還是在於變換的操作。
由於2-3樹的節點最多隻能存放2個元素,當有三個元素(四節點)的時候就需要進行變換。
2、紅黑樹與2-3樹的等價性
紅黑樹和2-3之間可以進行等價轉換。
通過上面的等價轉換可以看出來,定義紅色節點都是向左傾斜。用過表示節點的顏色來識別該節點是否是紅色節點。
對於我們上面的2-3樹我們可以對其進行轉換,如下圖:
根據上面的圖例,我們可以得出下面幾點結論:
- 每一個節點是要麼是紅色的,要麼是黑色的
- 每一個葉子節點(最後的空節點)均爲黑色的
- 根節點爲黑色節點
- 如果一個節點爲紅色的,那麼他的孩子節點均爲黑色的(否則觸發變換)
- 從任意一個節點到達葉子節點,經過的黑色節點數是相同的(絕對平衡性)
解讀性質:
- 對於性質一比較好理解,一個節點的顏色只有兩種狀態。
- 對於性質二這裏的葉子節點並不是指左右子樹均爲空的節點,這個性質應該叫做定義,紅黑樹中定義空節點的顏色就是黑色,這裏和性質三相吻合
- 對於性質三,和性質二是吻合的,對於一個空樹,它也是一種紅黑樹,那麼它既是葉子節點也是根節點,所以他的節點顏色也是黑色。
- 對於性質四,可以從2-3樹中得出結論,紅色節點的產生於3節點,紅色節點連接的子節點來自於下一個2節點或者3節點,對於2節點來說,它本身的顏色就是黑色的,對於3節點而言,拆分成紅黑結構的時候,是黑色的節點連接父親節點。所以可以得出性質四
- 對於性質五,可以通過紅黑樹的絕對平衡性得出,因此也可以拓展出一個結論,紅黑樹是一種保持黑平衡的的二叉樹
3、紅黑樹之增加元素
由於紅黑樹和2-3具有等價的關係,所以添加元素主要分爲向2節點和三節點進行元素的添加,兩者對應不同的情況。
3.1、向 2節點中添加元素
由於我們添加的節點都是紅色的節點,並且紅色節點一直保持左傾,對於下面這種情況,就需要進行一次旋轉操作。如果添加元素本身就是再左邊則無需變換。變換的操作就是和AVL樹一樣進行一次左旋轉操作,並且將顏色進行互換。如果新加入的節點本身就在左變則不需要進行變換。對應的函數爲 leftRotate()
3.2、向 3節點中添加元素
我們知道3節點添加位置主要包含三種,左邊、中間和右邊,下面逐一進行分析。
對於添加至右邊的情況:
對於這種情況,只需要將左右孩子節點的顏色全部變成黑色即可,我們在前面說過,新生成的父親節點要去和上面的節點繼續去融合,融合就意味着該節點的顏色爲紅色,也是一種類似的顏色互換的形式。對應的函數稱之爲顏色反轉,對應的函數爲flipColor()
對於添加至左邊的情況:
對於添加至中間的情況:
添加至中間的過程是一個組合的過程,可以先看成2節點的左旋轉過程和3節點的右旋轉過程。
3.3、總結
具體的添加元素操作可以直接使用下面這張圖,便於理解。
4、紅黑樹的實現
4.1、內部類的實現
紅黑樹和二分搜索樹的節點函數大致相同,只不過增加了對節點顏色的標識。
節點內部類的實現:
private class Node{ //內部類
public K key;
public V value;
public Node left, right;
public boolean color;
public Node(K key, V value){ // 節點信息的初始化
this.key = key;
this.value = value;
left = null;
right = null;
color = RED; // 新建的節點永遠是融合節點,紅色節點
}
}
4.2、基本結構以及函數實現
紅黑樹的基本架構程序實現:
public class RBTree<K extends Comparable<K>, V extends Comparable<V>>{
private static final boolean RED = true;
private static final boolean BLACK = false;
private class Node{
//內部類 省略
}
private Node root;
private int size;
public RBTree(){
root = null;
size = 0;
}
}
對於紅黑樹這種結構,我們增加了對顏色的判斷,所有我們引入isRed函數來判斷這個節點是否是紅色的。
程序實現:
private boolean isRed(Node node) {
if (node == null)
return BLACK;
return node.color;
}
基本輔助函數的實現,主要是對成員變量的一個get操作以及判斷紅黑樹是否爲空。
程序實現:
public int getSize() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
4.3、增加元素
我們根據上面的性質可以得到,根節點的顏色必須爲黑色,所以添加完元素後的根節點我們需要手動指定爲黑色,因爲我們新增的節點永遠是紅色的,所以我們需要手動將root變爲黑色,調用方式仍然是調用私有遞歸函數。
public void add(K key, V value) {
root = add(root, key, value);
root.color = BLACK; //手動將根節點變爲黑色
}
在2節點中添加元素,並且在節點右邊添加元素會觸發左旋轉,進而保證紅色節點的左傾性。
左旋轉程序實現:
private Node leftRotate(Node node) {
Node x = node.right;
// 左旋轉
node.right = x.left;
x.left = node;
//顏色互換
x.color = node.color;
node.color = RED;
return x;
}
在3節點中添加元素涉及左中右三種情況,上面講過,在右邊添加元素觸發顏色反裝。
顏色反轉程序實現:
private void flipColors(Node node) {
node.color = RED;
node.left.color = BLACK;
node.right.color = BLACK;
}
在向三節點中最左邊添加元素,觸發右旋轉過程。右旋轉過程中還要進行一次顏色反轉。
右旋轉程序實現:
private Node rightRotate(Node node) {
Node x = node.left;
//右旋轉
node.left = x.right;
x.right = node;
//顏色互換
x.color = node.color;
node.color = RED;
return x;
}
其他的添加元素的變換都是基於顏色變換,左右旋轉組合而來的。
具體的調用方法和AVL樹相同,在增加完元素的時候,對元素進行判斷,是一個在回朔的過程中進行操作。
增加函數的程序實現:
private Node add(Node node, K key, V value) {
if (node == null){
size++;
return new Node(key, value);
}
//首先進行元素的添加
if (key.compareTo(node.key) < 0)
node.left = add(node.left, key, value);
else if (key.compareTo(node.key) > 0)
node.right = add(node.right, key, value);
else
node.key = key;
//添加完成後,維護平衡性
//左節點爲黑,右節點爲紅
if (isRed(node.right) && !isRed(node.left))
node = leftRotate(node);
//左節點爲紅,左節點的左節點也爲紅
if (isRed(node.left) && isRed(node.left.left))
node = rightRotate(node);
//左右節點均爲紅
if (isRed(node.left) && isRed(node.right))
flipColors(node);
return node;
}
5、時間複雜度分析
從嚴格意義上講,紅黑樹並不是一種嚴格的平衡二叉樹。在最差的情況下,紅黑樹的高度爲2log(n),這是因爲在最差的情況下,每一個黑節點都有一個紅色節點,但是由於時間複雜度不考慮紅黑樹的時間複雜度也是O(log(n))級別的。
適應場景:
紅黑樹適應於添加刪除元素頻繁的場景。而對於查詢元素來說,紅黑樹並不是嚴格意義上的平衡樹,在最壞的情況樹的高度可以達到2log(n),所以說不同的場景適應於不同的算法。但是綜合性能來說的話,紅黑樹的性能任然高於一些其他的樹結構。
最後
更多精彩內容,大家可以轉到我的主頁:曲怪曲怪的主頁
或者關注我的微信公衆號:TeaUrn
源碼地址:可在公衆號內回覆 數據結構與算法源碼 即可獲得。