1. 程式人生 > >紅黑樹分析 清晰直白

紅黑樹分析 清晰直白

compareto tco 實現 info 左旋 exce 默認 返回 每一個

概念

紅黑樹(Red-Block Tree)是一種近似平衡的二叉樹,因此擁有較高的查詢效率,但正因為是一棵近平衡樹,因此在插入或刪除節點時,會結構調整(變色,左旋,右旋),使其接近平衡,從而降低效率.
本文以TreeMap為例說明,TreeMap用紅黑樹構建,所以查詢性能較高,時間復雜度為O(lgn),,而HashMap和LinkHashMap的時間復雜度都為O(n)(當hash不沖突時時間復雜度為O(1),但數量多起來後hash沖突顯示不是我們能控制的,故寫為O(n)),顯然查詢時比TreeMap耗時,關於時間復雜度分析,可移步到:時間復雜度分析 理解

**重點:**紅黑樹擁有3特征,6種行為,行為的存在使得樹在結構調整時,讓樹符合三種特征.這就是紅黑樹左旋,右旋,變色,原理,至於怎麽設定的,就是發明者 Rudolf Bayer 的厲害的地方了.

特征:

1.根節點必須是黑色
2.紅色節點不能連續(即紅節點的父子節點都得是黑色)
3.對於每個節點,從該節點到樹末梢(為null的節點),都有相同數量的黑色節點.
推導結論:一個節點到末端的最長路徑不大於最小路徑的2倍.

行為(就是源碼(本文jdk1.8)的實現方式,6種情況):看下文結構調整.
紅黑樹樣子:
技術分享圖片

正文:

get():
get(key)通過key查找,內部調getEntry(key),TreeMap每一個節點是一個Entry,有如下屬性,可以像鉤子一樣構成一棵樹.

  static final class Entry<K, V> implements java.util.Map.Entry<K,V{
        K key;
        V value;
        TreeMap.Entry
<K, V> left; TreeMap.Entry<K, V> right; TreeMap.Entry<K, V> parent; boolean color = true; }

其中getEntry()方法做了些操作:支持兩種比較器,如果在構造中傳入比較器comparator則使用,否則使用默認實現的SortedMap中的comparator,通過key值進行比對,直至找到entry返回entry.value,否則為null.

 1  final TreeMap.Entry<K, V> getEntry(Object var1) {
2 if (this.comparator != null) { 3 return this.getEntryUsingComparator(var1); 4 } else if (var1 == null) { 5 throw new NullPointerException(); 6 } else { 7 Comparable var2 = (Comparable)var1; 8 TreeMap.Entry var3 = this.root; 9 10 while(var3 != null) { 11 int var4 = var2.compareTo(var3.key); 12 if (var4 < 0) {//向左 13 var3 = var3.left; 14 } else { 15 if (var4 <= 0) {//找到了 16 return var3; 17 } 18 19 var3 = var3.right;//向右 20 } 21 } 22 23 return null; 24 } 25 }

put()

插入和刪除操作是結構變動的原因,此處以插入說明.

 1  public V put(K var1, V var2) {
 2         TreeMap.Entry var3 = this.root;
 3         if (var3 == null) {
 4             this.compare(var1, var1);
 5             this.root = new TreeMap.Entry(var1, var2, (TreeMap.Entry)null);
 6             this.size = 1;
 7             ++this.modCount;
 8             return null;
 9         } else {
10             Comparator var6 = this.comparator;
11             int var4;
12             TreeMap.Entry var5;
13             if (var6 != null) {
14                 do {
15                     var5 = var3;
16                     var4 = var6.compare(var1, var3.key);
17                     if (var4 < 0) {
18                         var3 = var3.left;
19                     } else {
20                         if (var4 <= 0) {
21                             return var3.setValue(var2);
22                         }
23 
24                         var3 = var3.right;
25                     }
26                 } while(var3 != null);
27             } else {
28                 if (var1 == null) {
29                     throw new NullPointerException();
30                 }
31 
32                 Comparable var7 = (Comparable)var1;
33 
34                 do {
35                     var5 = var3;
36                     var4 = var7.compareTo(var3.key);
37                     if (var4 < 0) {
38                         var3 = var3.left;
39                     } else {
40                         if (var4 <= 0) {
41                             return var3.setValue(var2);
42                         }
43 
44                         var3 = var3.right;
45                     }
46                 } while(var3 != null);
47             }
48 
49             TreeMap.Entry var8 = new TreeMap.Entry(var1, var2, var5);
50             if (var4 < 0) {
51                 var5.left = var8;
52             } else {
53                 var5.right = var8;
54             }
55 
56             this.fixAfterInsertion(var8);//結構調整
57             ++this.size;
58             ++this.modCount;
59             return null;
60         }
61     }

插入分兩步,第一步找位置,然後插入,沒什麽好說的,第二步是重點:結構調整.fixAfterInsertion方法如下:

 1 private void fixAfterInsertion(TreeMap.Entry<K, V> var1) {
 2         var1.color = false;
 3 
 4         while(var1 != null && var1 != this.root && !var1.parent.color) {
 5             TreeMap.Entry var2;
 6             if (parentOf(var1) == leftOf(parentOf(parentOf(var1)))) {//插入節點的父節點是爺爺節點的左節點
 7                 var2 = rightOf(parentOf(parentOf(var1))); //xi小叔節點
 8                 if (!colorOf(var2)) {
 9                     setColor(parentOf(var1), true);        //情況1
10                     setColor(var2, true);                        //:上色
11                     setColor(parentOf(parentOf(var1)), false);
12                     var1 = parentOf(parentOf(var1));        //獲取爺爺節點,繼續while中調整
13                 } else {
14                     if (var1 == rightOf(parentOf(var1))) {    //情況2
15                         var1 = parentOf(var1);//若x小叔節點是黑色或null,並且current插入的位置是右邊,則左旋轉,父節點變黑.......以下不再贅述
16                         this.rotateLeft(var1);
17                     }
18 
19                     setColor(parentOf(var1), true);        //情況3
20                     setColor(parentOf(parentOf(var1)), false);
21                     this.rotateRight(parentOf(parentOf(var1)));
22                 }
23             } else {
24                 var2 = leftOf(parentOf(parentOf(var1)));
25                 if (!colorOf(var2)) {
26                     setColor(parentOf(var1), true);    //情況4
27                     setColor(var2, true);
28                     setColor(parentOf(parentOf(var1)), false);
29                     var1 = parentOf(parentOf(var1));
30                 } else {
31                     if (var1 == leftOf(parentOf(var1))) {        //情況5
32                         var1 = parentOf(var1);
33                         this.rotateRight(var1);
34                     }
35 
36                     setColor(parentOf(var1), true);        //情況6
37                     setColor(parentOf(parentOf(var1)), false);
38                     this.rotateLeft(parentOf(parentOf(var1)));
39                 }
40             }
41         }
42 
43         this.root.color = true;
44     }

源碼很清晰,調整的6種行為,主要通過三個手段,變色,左旋,右旋,交互使用,使得樹最終滿足三個特征.

**右旋圖解示例:**
技術分享圖片

**左旋圖解示例:**
技術分享圖片

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

我不能保證理解都是對的和實踐都是最佳的,這是個人的一些理解和實踐,如發現問題,請聯系筆者做出更改,交流->分享->進步.

認真工作,熱愛生活.享受現在,擁抱未來~

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

紅黑樹分析 清晰直白