在樹型的查找中,咱們知道二叉查找樹的查找效率很不錯,可是此樹右個缺陷,就是對基本有序的樹查找起來變成了二分查找法.效率低下.後來出現了平衡二叉樹,解決了這個問題,但平衡二叉樹不管是實現,仍是其爲了維護左右子樹高度差問題的維護實現進而致使效率低下,進而產生了紅黑樹.java
如上圖,咱們分析下這兩個圖:node
圖1是一個不可能的紅黑樹,由於最低下的節點3和6的顏色是黑色,這種節點是不可能這樣添加上去的,還有每條路徑不平衡,2的左子樹雖然是個空節點,可是紅黑樹的葉子節點,所以其黑色高度爲1,可是右邊的紅黑樹高度明顯大於1,所以咱們有這樣的結論:框架
2. 圖2是一個新插入節點3的典型的表明圖,插入節點三之後,違反了性質4,則將節點2,5變爲黑色,將4變爲紅色,而後再將4變爲黑色便可.藉此,咱們分析一下插入節點的修復狀況:(p:parent,g:grandfather,u:uncle) 1. 當插入節點是根節點時,直接將顏色變爲黑色便可. 2. 當`p.color==BLACK`,而插入的節點爲紅色,對整個樹不影響,不作調整. 3. 當`p.color==RED`,則p原來必然沒有孩子,所以新插入的節點node是惟一孩子.`p.color==RED`->`g.color==BLACK(性質4)`->`u.color==RED(性質5)`,則將p,u顏色設置爲黑色,將g顏色設置爲紅色,此時,問題變爲g對整個樹的影響,不同了,後面討論g的變化分類. 4. g變爲了紅色對整個樹的影響,測試將g設置爲新的節點node,注意這和插入不同,這個節點是本來就有的.(此時對應插入節點的狀況1,2同樣不討論,咱們討論此時node節點的父親p的顏色是紅色的狀況,`p.color==RED`->`bro.color==BLACK`->`g.color==BLACK`->u可能爲紅色也可能爲黑色,注意,此時並無違反性質5,影響的只是性質4,兩個連續的紅色節點.此時處理的關鍵咱們發現是u節點,所以對u分狀況討論) 1. 當`u.color==RED`,繼續循環調用. 2. 當`u.color==BLACK`,見我前面的紅黑樹一節的說明,咱們此時須要對節點g進行左旋(`p==g.right`)或右旋(`p==g.left`),可是此時由個問題,咱們旋轉後不但願繼續出現繼續違反性質4(兩個節點爲紅色),所以須要對節點node是左子樹仍是右子樹分狀況討論. - 當`p==g.left` - 當`node==g.left`,咱們直接右旋,發現問題解決,OK! - 當`node==g.right`,咱們直接右旋,發現出現了節點g和bro同時爲紅色,且bro爲g的左子樹,違反性質4,這樣的左旋確定是有問題的.具體往下再不討論,讀者能夠本身去想,咱們得出的結論就是先將p節點左旋,而後再g節點右旋.而後咱們會獲得一個結論,此時的節點node變成了原來g節點的位置.爲此,咱們構造一顆樹驗證一下. ```java @Test public void testRBT() { TreeMap<Integer, String> map = new TreeMap<>(); map.put(9, 9 + ""); map.put(3, 3 + ""); map.put(10, 10 + ""); map.put(1, 1 + ""); map.put(6, 6 + ""); map.put(4, 4 + ""); map.put(8, 8 + ""); assertThat(map.getFirstEntry().getKey(), is(9)); map.put(5, 5 + ""); assertThat(map.getFirstEntry().getKey(), is(6)); } ``` 咱們的結論被驗證. - 當`p==g.right`鏡像問題,再也不作討論. 3. 綜上: 咱們分析一下整個插入過程,把能合併的合併.合併完以後就是我前一節紅黑樹所討論的狀況.在此,咱們再綜合一下. - 當插入節點是根節點,變爲黑色(case 1) - 當`p.color==BLACK`,無需操做 - 當`p.color==RED`時: - 當`u.color==RED`,遞歸解決(case 2) - 當`u.color==BLACK`,若node節點和其父節點都是左子樹或者都是右子樹,直接旋轉,不然須要先行處理,再旋轉.(case 3) 咱們給出這樣的框架代碼:
void fixInsertiong(Node node){ Node p,u,g; while(node!=root&&node.parent.color==RED){ p=node.parent; g==node.parent; if(p==g.left){ u=g.right; //case 2 if(u.color==RED){ u.color=BLACK; p.color=BLACK; g.color=RED; node =g; } //case 3 else{ if(node==p.right){ rotateLeft(p); Node tmp=p; p=node; node=tmp; } p.color=BLACK; g.color=RED; rotateRight(g); } }else{ u=g.left; //case 2 if(u.color==RED){ u.color=BLACK; p.color=BLACK; g.color=RED; node =g; } //case 3 else{ if(node==p.left){ rotateRight(p); Node tmp=p; p=node; node=tmp; } p.color=BLACK; g.color=RED; rotateLeft(g); } } } } //case 1 root.color==BLACK; }
思路,因爲新插入節點和及祖父節點變爲紅色時都須要調整,咱們合併爲一種狀況,只考慮祖父節點變爲紅色,對整個樹的影響,此時node.color==p.color==RED
,bro.color==g.color==BLACK
,故須要對u分顏色討論,可是u的獲取和p是左子樹仍是右子樹有關,故先對p是左子樹仍是右子樹分類,再對u.color分類,而後旋轉,爲了保證旋轉後不會出現兩個連續的紅色,須要檢查node節點和p是否都爲左子樹或者同爲右子樹.若是是直接旋轉,若是不是,先逆向旋轉,再旋轉,這種狀況獲得的node通常變成了g的位置.測試