紅黑樹總結

紅黑樹總結

紅黑樹用來解決什麼問題?

在樹型的查找中,咱們知道二叉查找樹的查找效率很不錯,可是此樹右個缺陷,就是對基本有序的樹查找起來變成了二分查找法.效率低下.後來出現了平衡二叉樹,解決了這個問題,但平衡二叉樹不管是實現,仍是其爲了維護左右子樹高度差問題的維護實現進而致使效率低下,進而產生了紅黑樹.java

那些紅黑樹是不可能的?

輸入圖片說明

如上圖,咱們分析下這兩個圖:node

  1. 圖1是一個不可能的紅黑樹,由於最低下的節點3和6的顏色是黑色,這種節點是不可能這樣添加上去的,還有每條路徑不平衡,2的左子樹雖然是個空節點,可是紅黑樹的葉子節點,所以其黑色高度爲1,可是右邊的紅黑樹高度明顯大於1,所以咱們有這樣的結論:框架

    • 當該節點沒有孩子節點
      • 該節點爲紅色,其父節點爲黑色,兄弟節點爲紅色
      • 該節點爲黑色,此種節點通常是通過變換得來的,新插入的節點不多是紅色的.
    • 當該節點只有左孩子或者右孩子之一,若該節點是黑色,其惟一孩子必然爲紅色,且孩子節點的左右子樹必然爲空節點.(這是由性質5決定的,爲了左右子樹的平衡,必須這樣)
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的位置.測試

相關文章
相關標籤/搜索