紅黑樹原理詳解

前言:

         之所以要寫這篇文章,第一個目的是爲了各位朋友在查看我寫的源代碼之前有一個可以理解理論的文章因爲紅黑樹還是有點難的,

如果不想搞懂理論,而直接看代碼,那絕對是雲裏霧裏,不知所云。第二個目的是我覺得網上雖然後不少我文章也在講,但是我就是理解

不上有點困難,在我參考了很多文章之後,認真閱讀才慢慢摸透了其中的原理,所以我想用自己的方式來表達,希望有助於各位的朋友理解。

你可以在這裏獲得配套源代碼


紅黑樹由來:

         他是在1972年 由Rudolf Bayer發明的,他稱之爲“對稱二叉B樹”,它現代的名字是Leo J. Guibas和 Robert Sedgewick 於1978

年寫的一篇論文中獲得的。它是複雜的,但它的操作有着良好的最壞情況運行時間,並且在實踐中是高效的: 它可以在O(log n)時間內做查找,

插入和刪除,這裏的n 是樹中元素的數目。


紅黑樹性質:

1. 每個結點或紅或黑。

2. 根結點爲黑色。

3. 每個葉結點(實際上就是NULL指針)都是黑色的。

4. 如果一個結點是紅色的,那麼它的周邊3個節點都是黑色的。

5. 對於每個結點,從該結點到其所有子孫葉結點的路徑中所包含的黑色結點個數都一樣。


討論的前提:

1,我們只討論往樹的左邊和從樹的左邊刪除的情況,與之對稱的情況一樣。

2,假設我們要刪除一個元素的方法都是採取刪除後繼節點,而非前驅節點。

3,NL或全黑表示黑空節點,也可以不用畫出。

4,“=>”這個符號我們用來表示“變成”的意思。

一. 插入

當紅黑樹中沒有節點的時候,新節點直接塗黑就可以了。

當樹中已有節點,我們就將新節點塗紅,並且底下掛兩個黑空節點。

1.1 新節點的父親爲黑色

這種情況最簡單,只接插入將新節點可以了,不會出現紅色警戒。

1.2 新節點的父親爲紅色

這種情況出現紅色警戒,並且通過紅色的父親,我們可以推出一定有一個黑色的父, 並且父親不可能爲樹根(樹根必須爲黑)。

這種情況需要修復。

1.2.1 新節點的叔叔是紅色。(紅叔)

圖1.2.1-1


圖1.2.1-2

註解:在這種情況下,我們可以通過這樣的方式來修復紅黑樹的性質。因爲遇到紅 色警戒所以我們首先可以想到的就是將父親變成黑色,但這樣祖父的左子樹的黑高 就增加了,爲了達到祖父的平衡,我們紅叔變成黑色,這樣祖父就平衡了。但是整 個祖父這顆樹的高度增高了,所以再此將祖父的顏色變成紅色來保持祖父這顆樹的 高度不變。因爲祖父變成了紅色,因此往上遍歷。

       方法:父=>黑;叔=>黑;祖=>紅;往上遍歷;

1.2.2 新節點的叔叔是黑色(黑叔)

圖1.2.2-1

圖1.2.2-2

註解:首先可以說明的是,這種情況下我們都可以通過改變顏色和旋轉的方式到達 平衡,並且不再出現紅色警戒,因爲無需往上遍歷。圖1.2.2-1:首先我們將紅父變 成黑色,祖父變成紅色,然後對祖父進行右旋轉。這樣我們可以看到,整顆樹的黑 高不變,並且這顆樹的左右子樹也達到平衡。新的樹根爲黑色。因此無需往上遍歷。

方法:圖1.2.2-1  父=>黑;祖=>紅;祖父右旋轉;

                 圖1.2.2-2    新=>黑;祖=>紅;父左旋轉;祖右旋轉;


插入我們就算做完了,與之對稱的右邊插入的情況完全一樣,請自己下來分析;

一. 刪除

刪除是比較經典但也是最困難的一件事了,所以我們必須一步一步地理解。爲了中途思想不混亂,請始終記住一點,下面我們刪除的節點都已經表示的是實際要刪除的後繼節點了。因此可以得出一下結論。

    首先,可以肯定的是我們要刪除的節點要麼是紅色,要麼是黑色。

     其次,既然我們要刪除的結點是後繼節點,那麼要刪除的節點的左子樹一定爲空。所以當刪除的節點爲黑色時只剩下兩種情況。

     最後,如果刪除的節點爲紅色,那麼它必爲葉子節點。(自己好好想象爲什麼)。

請在看下面的內容前先牢記上面的結論,這樣更加方便讓你理解下面的知識。

a:當刪除的節點爲黑色時

               刪黑a                刪黑b


b:當刪除的節點爲紅色時

      上面的幾附圖都是很簡單的。因爲你可以將空節點 去掉不看。所就形成了要 刪除的節點要麼有一個右孩子,要麼爲葉子節點。


下面我們就開始真正的刪除操作了。

2.1 刪除紅色節點

註解:這種情況是最簡單的,因爲根據我們可以推出子節點     一定爲空, 也就是說刪除的紅色節點爲葉子節點。只需將這個舊節點的右孩子付給父親的左孩子就 可以了,高度不變。

方法:略


2.2 刪除黑色節點

          遇到黑色節點情況就將變得複雜起來,因此我們一定要慢慢來,仔細分析。

          2.2.1當刪除的節點有一個紅色子孩子

註解:這種情況其實就是上面我們分析的三種情況之一,如圖""。這種情況 是非常簡單的,只需將舊節點的右孩子取代舊節點,並將子孩子的顏色變爲黑色, 樹平衡;

        方法:子取代舊;子=>黑;

2.2.2當刪除的節點無左右孩子

這種情況其實就是上面我們分析的三種情況之一,如圖"刪黑a"。我們推出子節點 一定爲空,請務必記住這點,不然在後面你將很容易被混淆,父親的顏 色我們標記爲綠色,是表示,父親的顏色可爲紅或黑。黃色的子節點其實就 是一個黑空節點,這樣方便後面分析。

a:紅兄


註解:當我們刪除的節點擁有一個紅色的兄弟時,這種情況還相對比較簡單,因爲 兄弟爲黑色,我們可以推出父親一定爲黑色。因爲父節點的左樹高度減一,所 以我們可以通過左旋轉父節點,來將節點1旋轉到左邊來恢復左邊的高度。然 後將父變成紅,兄變成黑。這樣整顆樹的高度不變,父節點也平衡記住子節點 爲空所以可以刪除看,這樣便於理解。       

        方法:父=>紅;兄=>黑;左旋轉父節點;


b :黑兄

      遇到黑兄就又麻煩了,我們又必須引入要刪除的節點的侄子了。所以我們這裏 再次細分爲b1: 黑兄 雙黑侄 b2: 黑兄 左黑侄右紅侄 b3: 黑兄 右黑侄左紅侄。 可能你會問b4呢,雙紅侄的情況呢?其實雙紅侄的情況同屬於b2,b3的情況,所以 可以默認用 b2,b3其中一種情況來處理就可以了。

現在我們開始了

      b1黑兄 雙黑侄



註解:我們首先可以肯定的是父節點的左子樹高度減一了,所以我們必須想方設法 來彌補這個缺陷。如果我們把父節點的右子樹高度也減一(兄變成紅色)那麼 父節點這顆樹就可以保持平衡了,但整顆樹的高度減一,所以我們可以判斷, 如果父親是紅色,那麼我們可以通過把父親變成黑色來彌補這一缺陷。但如果 父親是黑色呢,既然遇到到黑色了我們就只好往上遍歷了。

方法:兄=>紅;子=黑;    紅父=>黑;

                                  往上遍歷(黑父);

補充:其實子節點就是空節點,沒有必要變。就算遍歷上去,父節點也爲黑

b2黑兄 左黑侄右紅侄


註解:綠色表示,顏色不影響修復的方式。依然我們可以肯定父節點的左子樹高度減一,所以我們可以通過將父節點旋轉下來並且變爲黑色來彌補,但由於兄弟被旋轉上去了,又導致右子樹高度減一,但我們這有一個紅侄,所以可以通過紅侄變成黑色來彌補。父親所在位置的顏色不變;(子爲空)
方法:兄=>父色;父=>黑;侄=>黑;(子=>黑);左旋轉父節點;

b3 黑兄 左紅侄右黑侄


註解:綠色表示,顏色不影響修復的方式。依然我們可以肯定父節點的左子樹高度減一,同樣我們通過父節點左旋轉到左子樹來彌補這一缺陷。但如果直接旋轉的話,我們可以推出左右子樹將不平衡(黑父),或者兩個紅色節點相遇(紅父);這樣將會更加的複雜,甚至不可行。因此,我們考慮首先將兄弟所在子樹右旋轉,然後再左旋轉父子樹。這樣我們就可以得到旋轉後的樹。然後通過修改顏色來使其達到平衡,且高度不變。
方法:侄=>父色;父=>黑;右旋轉兄;左旋轉父;


總結:

如果我們通過上面的情況畫出所有的分支圖,我們可以得出如下結論

插入操作:解決的是 紅-紅 問題

刪除操作:解決的是 黑-黑 問題

即你可以從分支圖中看出,需要往上遍歷的情況爲紅紅(插入);或者爲黑黑黑(刪除)的情況,,如果你認真分析並總結所有的情況後,並堅持下來,紅黑樹也就沒有想象中的那麼恐怖了,並且很美妙;


程序樣列:



點擊這裏下載源碼


聲明:

         此文檔爲《C語言常用數據結構源代碼全註解-紅黑樹源碼》所寫,此文檔遵循GNU FDL協議,你可以修改重發,但因保留原始版權信息;

         此文檔版本V1.0爲初次發佈,所以難面有錯誤的地方,如果你發現任何錯誤或缺點,非常感謝你發信息聯繫我。此文檔僅供學習使用。


參考文獻:

《百度百科 紅黑樹》                     地址:http://baike.baidu.com/view/133754.htm

《C#與數據結構-樹論—紅黑樹》地址:http://tech.ddvip.com/2008-12/1229486123100653_7.html

《資料結構與演算法(上)》             作者:呂學一

《資料結構與演算法(上)》             紅黑樹大部分圖片來源


發佈了32 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章