紅黑樹分析 清晰直白
概念
紅黑樹(Red-Block Tree)是一種近似平衡的二叉樹,因此擁有較高的查詢效率,但正因為是一棵近平衡樹,因此在插入或刪除節點時,會結構調整(變色,左旋,右旋),使其接近平衡,從而降低效率.
本文以TreeMap為例說明,TreeMap用紅黑樹構建,所以查詢效能較高,時間複雜度為O(lgn),,而HashMap和LinkHashMap的時間複雜度都為O(n)(當hash不衝突時時間複雜度為O(1),但數量多起來後hash衝突顯示不是我們能控制的,故寫為O(n)),顯然查詢時比TreeMap耗時,關於時間複雜度分析,可移步到: ofollow,noindex">時間複雜度分析 理解
**重點:**紅黑樹擁有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.
1final TreeMap.Entry<K, V> getEntry(Object var1) { 2if (this.comparator != null) { 3return this.getEntryUsingComparator(var1); 4} else if (var1 == null) { 5throw new NullPointerException(); 6} else { 7Comparable var2 = (Comparable)var1; 8TreeMap.Entry var3 = this.root; 9 10while(var3 != null) { 11int var4 = var2.compareTo(var3.key); 12if (var4 < 0) {//向左 13var3 = var3.left; 14} else { 15if (var4 <= 0) {//找到了 16return var3; 17} 18 19var3 = var3.right;//向右 20} 21} 22 23return null; 24} 25}
put()
插入和刪除操作是結構變動的原因,此處以插入說明.
1public V put(K var1, V var2) { 2TreeMap.Entry var3 = this.root; 3if (var3 == null) { 4this.compare(var1, var1); 5this.root = new TreeMap.Entry(var1, var2, (TreeMap.Entry)null); 6this.size = 1; 7++this.modCount; 8return null; 9} else { 10Comparator var6 = this.comparator; 11int var4; 12TreeMap.Entry var5; 13if (var6 != null) { 14do { 15var5 = var3; 16var4 = var6.compare(var1, var3.key); 17if (var4 < 0) { 18var3 = var3.left; 19} else { 20if (var4 <= 0) { 21return var3.setValue(var2); 22} 23 24var3 = var3.right; 25} 26} while(var3 != null); 27} else { 28if (var1 == null) { 29throw new NullPointerException(); 30} 31 32Comparable var7 = (Comparable)var1; 33 34do { 35var5 = var3; 36var4 = var7.compareTo(var3.key); 37if (var4 < 0) { 38var3 = var3.left; 39} else { 40if (var4 <= 0) { 41return var3.setValue(var2); 42} 43 44var3 = var3.right; 45} 46} while(var3 != null); 47} 48 49TreeMap.Entry var8 = new TreeMap.Entry(var1, var2, var5); 50if (var4 < 0) { 51var5.left = var8; 52} else { 53var5.right = var8; 54} 55 56this.fixAfterInsertion(var8);//結構調整 57++this.size; 58++this.modCount; 59return null; 60} 61}
插入分兩步,第一步找位置,然後插入,沒什麼好說的,第二步是重點:結構調整.fixAfterInsertion方法如下:
1 private void fixAfterInsertion(TreeMap.Entry<K, V> var1) { 2var1.color = false; 3 4while(var1 != null && var1 != this.root && !var1.parent.color) { 5TreeMap.Entry var2; 6if (parentOf(var1) == leftOf(parentOf(parentOf(var1)))) {//插入節點的父節點是爺爺節點的左節點 7var2 = rightOf(parentOf(parentOf(var1))); //xi小叔節點 8if (!colorOf(var2)) { 9setColor(parentOf(var1), true);//情況1 10setColor(var2, true);//:上色 11setColor(parentOf(parentOf(var1)), false); 12var1 = parentOf(parentOf(var1));//獲取爺爺節點,繼續while中調整 13} else { 14if (var1 == rightOf(parentOf(var1))) {//情況2 15var1 = parentOf(var1);//若x小叔節點是黑色或null,並且current插入的位置是右邊,則左旋轉,父節點變黑.......以下不再贅述 16this.rotateLeft(var1); 17} 18 19setColor(parentOf(var1), true);//情況3 20setColor(parentOf(parentOf(var1)), false); 21this.rotateRight(parentOf(parentOf(var1))); 22} 23} else { 24var2 = leftOf(parentOf(parentOf(var1))); 25if (!colorOf(var2)) { 26setColor(parentOf(var1), true);//情況4 27setColor(var2, true); 28setColor(parentOf(parentOf(var1)), false); 29var1 = parentOf(parentOf(var1)); 30} else { 31if (var1 == leftOf(parentOf(var1))) {//情況5 32var1 = parentOf(var1); 33this.rotateRight(var1); 34} 35 36setColor(parentOf(var1), true);//情況6 37setColor(parentOf(parentOf(var1)), false); 38this.rotateLeft(parentOf(parentOf(var1))); 39} 40} 41} 42 43this.root.color = true; 44}
原始碼很清晰,調整的6種行為,主要通過三個手段,變色,左旋,右旋,互動使用,使得樹最終滿足三個特徵.
**右旋圖解示例:**

**左旋圖解示例:**

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
我不能保證理解都是對的和實踐都是最佳的,這是個人的一些理解和實踐,如發現問題,請聯絡筆者做出更改,交流->分享->進步.
認真工作,熱愛生活.享受現在,擁抱未來~
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||