【演算法】紅黑樹插入資料(變色,左旋、右旋)(二)
本人菜雞一隻,正在更新紅黑樹系列的文章。
該系列到現在暫只有3篇文章:
【演算法】紅黑樹(二叉樹)概念與查詢(一):https://blog.csdn.net/lsr40/article/details/85230703
【演算法】紅黑樹插入資料(變色,左旋、右旋)(二):https://blog.csdn.net/lsr40/article/details/85245027
【演算法】紅黑樹插入資料的情況與實現(三):https://blog.csdn.net/lsr40/article/details/85266069
如果想要在查詢的時候能夠使用到紅黑樹的查詢優化的時候,必須把資料先載入到紅黑樹中,載入到紅黑樹中其實就是put ,就是一個構建紅黑樹的過程!
學習怎麼構建紅黑樹之前,我們必須掌握幾個基本的知識!
1、紅黑樹在插入資料的時候,會先遍歷資料應該插入到哪個位置,插入的位置肯定在底部,不可能在中間突然插入一個值。
2、插入的資料一定是紅色的(因為要遵守紅黑樹的第五條規則,如果有一條分支增加了一個黑色節點,就會打破該規則)
3、插入之後,為了滿足規則4,就需要用到換色與左旋、右旋的操作了
換色,其實就是紅變黑,黑變紅,只需要讓某個物件的屬性改變就可以了,沒什麼好說的。
重要的是什麼是旋轉,為什麼要旋轉,什麼時候選擇左旋,什麼時候旋轉右旋?
1、旋轉分兩種:
-1.左旋
大家看如下三張圖,對於x做左旋
原始的樣子:
正在變換:
變換結束:
-2.右旋
大家看如下三張圖,對於y做右旋
原始的樣子:
正在變換:
變換結束:
所以,我們發現左旋和右旋是一個相對的操作。
關於紅黑樹旋轉的程式碼,其實很簡單,我大概說一下如何實現,其實每個節點有這麼幾個屬性:
1、父節點的指向
2、子節點的指向(有兩個,一個左子節點,一個右子節點)
3、該節點的顏色
4、該節點儲存的value(當然如果是map,那就是該節點的key和value都要存,然後按照key的大小來插入新節點)
所以當我們做旋轉的時候,只需要把該節點的父節點指向該節點的子節點,然後把子節點的一條腿接到該節點上。
詳情看TreeMap的原始碼:
左旋轉我加了中文註釋,大家可以對照,我上面畫的左旋轉的圖去理解旋轉的過程,java如何實現
/** From CLR */
//從TreeMap類中的2221行開始
private void rotateLeft(Entry<K,V> p) {
//這裡的p就是圖中綠色的x
if (p != null) {
//r就是圖中的y
Entry<K,V> r = p.right;
//x.right變成y.left
p.right = r.left;
//如果y的左腿不為空
if (r.left != null)
//設定y.left的父節點為x(必須雙向設定)
r.left.parent = p;
//x的父節點,變成了y的父節點
r.parent = p.parent;
//如果x的父節點為空,證明x就是根節點
if (p.parent == null)
//那麼y就變成了根節點
root = r;
//如果x是父親的左子節點,x的父親的左子節點就變成了y
else if (p.parent.left == p)
p.parent.left = r;
else
//否則x就是父親的右子節點,x的父親的右子節點就變成了y
p.parent.right = r;
//x變成了y的左子節點
r.left = p;
//x的父親變成了y
p.parent = r;
}
}
/** From CLR */
private void rotateRight(Entry<K,V> p) {
if (p != null) {
Entry<K,V> l = p.left;
p.left = l.right;
if (l.right != null) l.right.parent = p;
l.parent = p.parent;
if (p.parent == null)
root = l;
else if (p.parent.right == p)
p.parent.right = l;
else p.parent.left = l;
l.right = p;
p.parent = l;
}
}
當然,到現在我們還不知道到底為什麼要旋轉?
欲知後事如何,且看下回分解!
本人菜雞一隻,如果有筆誤或者自己理解的不到位的地方,還請各位看官批評指出,避免寫出不嚴謹,甚至誤導新人的文章!!