標籤:通過 紅色 步驟 map private 修複 tco png jdk
紅/黑樹狀結構是自平衡的排序樹,自平衡的優點是減少遍曆的節點,所以效率會高。如果是非平衡的二叉樹,當順序或逆序插入的時候,尋找動作很可能會遍曆n個節點紅/黑樹狀結構的規則很容易理解,但是維護這個規則難。一、規則1.每個節點要麼是紅色、要麼是黑色2.根節點一定是黑色3.紅色節點不可以連續出現(父節點、子節點不可同時為紅)4.從任意節點出發,到樹底的所有路線,途徑的黑節點數量必須相同在修改紅/黑樹狀結構的時候,切記要維護這個規則。一般預設插入紅色節點(除非是root節點),插入後再進行旋轉和顏色變換二、旋轉、變換技巧關於旋轉和顏色變換有幾種情況:1.插入root不會違反規則2.父黑插入節點的父節點是黑色,不會違反規則3.父紅插入節點的父節點是紅色,一定違反規則(違反規則3)(因為預設插入紅色節點),此時就需要修複紅/黑樹狀結構了。這種情況下又細分為幾種情況4.父紅,叔紅父節點和叔節點均為紅色(違反規則3)
這種情況下就把父節點和叔節點都改成黑色,然後曾節點改為紅色
可是此時,如果曾節點是根節點的話,那麼必須將曾節點轉為黑色。所以一般在修補紅/黑樹狀結構的方法的最後,會強制將根節點轉為黑色這種情況可能又會導致5.1的情況5.1父紅,叔黑,外側子孫父節點是紅色,叔節點是黑色或者null,且新增節點是曾節點的外側子孫(違反規則3)外側子孫:A點是B點的左-左-....-左或者右-右-..-右,那麼A是B的外側子孫,否則A是B的內側子孫符號解釋:N:新插入的節點,P:父節點,G:曾節點,U:叔節點
此時就需要將G點旋轉,這裡是右旋
不過此時顏色還有衝突,還要調整一下顏色將P與G的顏色對調,既P變為黑色,G變為紅色
總結一下,5.1的步驟:step1:P->黑step2:G->紅step3:將G旋轉5.1.1關於旋轉的方向旋轉有左旋右旋,具體是看父節點是曾節點的左節點還是右節點P是G的左節點,那麼就將G右旋(因為要把P移動到G的位置)P....G....右節點.....................G左旋5.2父紅,叔黑,內側子孫父節點是紅色,叔節點是黑色或者null,且新增節點是曾節點的內側子孫(違反規則3)外側子孫:A點是B點的左-左-....-左或者右-右-..-右,那麼A是B的外側子孫,否則A是B的內側子孫5.2跟5.1隻有一個內側外側的區別。內側子孫比外側要多做一次旋轉。目的是把內側子孫旋轉成外側子孫來做
這裡的N就是G的內側子孫,現在要把N變成G的外側子孫。將P旋轉(這裡是左旋),讓N旋轉到P的位置
之後的步驟就是和5.1處理外側子孫的一樣了。5.2.1內側轉外側的旋轉方向根據P點和N的相對位置,當N是P的右節點,則將P左旋,否則將P右旋目的是讓N旋轉到P的位置總結情況:1.插入的是根節點,不違反規則2.插入點的父節點是黑色,不違反規則3.插入點的父、叔節點是紅色,將父、叔轉成黑色,然後將曾節點轉成紅色4.插入點的父是紅色、叔節點是黑色或者null,通過旋轉和轉變顏色,注意內側外側子孫!三、分析TreeMap源碼jdk中的紅/黑樹狀結構實現是TreeMap。
每次put之後,都會調用這個方法去維護紅/黑樹狀結構的規則
private void fixAfterInsertion(Entry<K,V> x) { x.color = RED; while (x != null && x != root && x.parent.color == RED) {//父節點是紅色 if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {//父節點是曾節點的左節點 Entry<K,V> y = rightOf(parentOf(parentOf(x))); if (colorOf(y) == RED) {//父、叔節點都是紅色,情況4 //將父節點和叔節點變為黑色,曾節點變為紅色 setColor(parentOf(x), BLACK); setColor(y, BLACK); setColor(parentOf(parentOf(x)), RED); x = parentOf(parentOf(x)); } else {//父節點是紅色,叔節點是黑色或者null if (x == rightOf(parentOf(x))) {//內側子孫 x = parentOf(x); rotateLeft(x);//旋轉成外側子孫 } setColor(parentOf(x), BLACK); setColor(parentOf(parentOf(x)), RED); rotateRight(parentOf(parentOf(x)));//旋轉曾節點 } } else {//父節點是曾節點的右節點 Entry<K,V> y = leftOf(parentOf(parentOf(x))); if (colorOf(y) == RED) { setColor(parentOf(x), BLACK); setColor(y, BLACK); setColor(parentOf(parentOf(x)), RED); x = parentOf(parentOf(x)); } else { if (x == leftOf(parentOf(x))) { x = parentOf(x); rotateRight(x); } setColor(parentOf(x), BLACK); setColor(parentOf(parentOf(x)), RED); rotateLeft(parentOf(parentOf(x))); } } } root.color = BLACK;//強制將根節點轉成黑色}
查看原文:http://blog.zswlib.com/2016/11/01/jdk%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%e7%ba%a2%e9%bb%91%e6%a0%91-%e6%8f%92%e5%85%a5%e7%af%87/
jdk源碼分析紅/黑樹狀結構——插入篇