1. 程式人生 > >【演算法】紅黑樹插入資料(變色,左旋、右旋)(二)

【演算法】紅黑樹插入資料(變色,左旋、右旋)(二)

本人菜雞一隻,正在更新紅黑樹系列的文章。

該系列到現在暫只有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;
        }
    }

 

當然,到現在我們還不知道到底為什麼要旋轉?

欲知後事如何,且看下回分解!

本人菜雞一隻,如果有筆誤或者自己理解的不到位的地方,還請各位看官批評指出,避免寫出不嚴謹,甚至誤導新人的文章!!