紅黑樹詳解

紅黑樹

我們知道二叉查找樹有較高的查找速度,同時爲了避免單枝樹等情況,又希望該二叉樹接近於滿二叉樹,或者二叉樹的每一個節點的左、右子樹深度儘量相等,這樣的二叉樹稱爲平衡二叉樹。平衡二叉樹的常用實現方法有紅黑樹、AVL、替罪羊樹、Treap、伸展樹等。接下來我們看一下紅黑樹的原理。

定義

紅黑樹(英語:Red–black tree)是一種自平衡二叉查找樹,是在計算機科學中用到的一種數據結構,典型的用途是實現關聯數組。它在1972年由魯道夫·貝爾發明,被稱爲"對稱二叉B樹",它現代的名字源於Leo J. Guibas和Robert Sedgewick於1978年寫的一篇論文。紅黑樹的結構複雜,但它的操作有着良好的最壞情況運行時間,並且在實踐中高效:它可以在O(logN)時間內完成查找,插入和刪除,這裏的N是樹中元素的數目。

性質

紅黑樹是每個節點都帶有顏色屬性的二叉查找樹,顏色爲紅色或黑色。在二叉查找樹強制一般要求以外,對於任何有效的紅黑樹我們增加了如下的額外要求:

  1. 節點是紅色或黑色。
  2. 根是黑色。
  3. 所有葉子都是黑色(葉子是NULL節點)。
  4. 每個紅色節點的子節點一定是黑色。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點。)
  5. 從任一節點到其每個葉子的所有簡單路徑都包含相同數目的黑色節點。

這些約束確保了紅黑樹的關鍵特性:從根到葉子的最長的可能路徑不多於最短的可能路徑的兩倍長。結果是這個樹大致上是平衡的(紅黑樹是近似平衡的二叉排序樹)。因爲操作比如插入、刪除和查找某個值的最壞情況時間都要求與樹的高度成比例,這個在高度上的理論上限允許紅黑樹在最壞情況下都是高效的,而不同於普通的二叉查找樹。

要知道爲什麼這些性質確保了這個結果,注意到性質4導致了路徑不能有兩個毗連的紅色節點就足夠了。最短的可能路徑都是黑色節點,最長的可能路徑有交替的紅色和黑色節點。因爲根據性質5所有最長的路徑都有相同數目的黑色節點,這就表明了沒有路徑能多於任何其他路徑的兩倍長

在很多樹數據結構的表示中,一個節點有可能只有一個子節點,而葉子節點包含數據。用這種範例表示紅黑樹是可能的,但是這會改變一些性質並使算法複雜。爲此,本文中我們使用"nil葉子"或"空(null)葉子",它不包含數據而只充當樹在此結束的指示。這些節點在繪圖中經常被省略,導致了這些樹好像同上述原則相矛盾,而實際上不是這樣。與此有關的結論是所有節點都有兩個子節點,儘管其中的一個或兩個可能是空葉子。

如下圖所示就是一顆典型的紅黑樹:
在這裏插入圖片描述

因爲每一個紅黑樹也是一個特化的二叉查找樹,因此紅黑樹上的只讀操作與普通二叉查找樹上的只讀操作相同。然而,在紅黑樹上進行插入操作和刪除操作會導致不再匹配紅黑樹的性質。恢復紅黑樹的性質需要少量(log n))的顏色變更(實際是非常快速的)和不超過三次樹旋轉(對於插入操作是兩次)。雖然插入和刪除很複雜,但操作時間仍可以保持爲(log n)次。

插入

我們首先以二叉查找樹的方法增加節點並標記它爲紅色。(如果設爲黑色,就會導致根到葉子的路徑上有一條路上,多一個額外的黑節點,這個是很難調整的。但是設爲紅色節點後,可能會導致出現兩個連續紅色節點的衝突,那麼可以通過顏色調換(color flips)和樹旋轉來調整。)下面要進行什麼操作取決於其他臨近節點的顏色。同人類的家族樹中一樣,我們將使用術語叔父節點來指一個節點的父節點的兄弟節點。注意:

  • 性質1和性質3總是保持着。
  • 性質4只在增加紅色節點、重繪黑色節點爲紅色,或做旋轉時受到威脅。
  • 性質5只在增加黑色節點、重繪紅色節點爲黑色,或做旋轉時受到威脅。

插入操作總體可分爲以下5中情況:
注意:圖中節點 I表示插入節點,P表示父節點,G表示祖父節點,U表示叔父節點。

case1: 空樹

只需將該節點設置爲根節點,同時顏色置爲黑色。
在這裏插入圖片描述

case2: 插入節點的父節點P是黑色

由於新插入節點的父節點是黑色,對於紅黑樹的性質沒有影響固無需做相應的調整
在這裏插入圖片描述

case3: 插入節點的父節點和叔父節點都是紅色

注意下面是對稱結構,故做同一情況處理。
在這裏插入圖片描述
新插入節點後不滿足性質4紅色節點不能連續。則我們可以將父節點P和叔父節點U設爲黑色並重繪祖父節點G設爲紅色(用來保持性質5)。更改後如下圖所示
在這裏插入圖片描述
現在父節點P變爲了黑色。因爲通過父節點P或叔父節點U的任何路徑都必定通過祖父節點G,在這些路徑上的黑節點數目沒有改變(性質5)。但是,紅色的祖父節點G可能是根節點,這就違反了性質2,也有可能祖父節點G的父節點是紅色的,這就違反了性質4。爲了解決這個問題,我們在祖父節點G上遞歸地進行調整。(把G當成是新加入的節點進行各種情形的檢查)。

case4:父節點P是紅色而叔父節點U是黑色或沒有(null節點),並且新節點I是其父節點的左孩子,而父節點P又是其父節點G的左孩子。

如下圖所示,這裏對稱結構就沒有給出來了。
在這裏插入圖片描述
這裏我們將圖中的情況用null節點補以便觀察整個調整過程:

  1. 將父節點P設置爲黑色
  2. 將祖父節點G設置爲紅色
    在這裏插入圖片描述
  3. 對G進行右旋
    在這裏插入圖片描述

case5: 父節點P是紅色而叔父節點U是黑色或沒有(null節點),並且新節點I是其父節點P的右子節點而父節點P又是其父節點G的左子節點

如下圖所示:
在這裏插入圖片描述
調整方法:

  1. 將P進行左旋
  2. 然後將P作爲當前節點
  3. 變爲case4,根據case4繼續調整
    在這裏插入圖片描述
    在這裏插入圖片描述
    到這裏整個插入的情況就說完了,以上各個情況可能會在調整過程中由一種場景切換到另一種場景。

刪除

對於二叉查找樹,在刪除帶有兩個非葉子兒子的節點的時候,我們要麼找到它左子樹中的最大元素、要麼找到它右子樹中的最小元素,並把它的值轉移到要刪除的節點中(如在這裏所展示的那樣)。我們接着刪除我們從中複製出值的那個節點( 在"被刪除節點"有兩個非空子節點的情況下,它的替換節點不可能是雙子非空)。因爲只是複製了一個值(沒有複製顏色),不違反任何性質,這就把問題簡化爲如何刪除最多有一個兒子的節點的問題。它不關心這個節點是最初要刪除的節點還是我們從中複製出值的那個節點。

如果使用標籤m表示要刪除的節點;c表示m的選定替換M的子節點,我們也將c其稱爲“子節點”

  1. 如果我們刪除一個紅色節點M(此時該節點的兒子將都爲葉子節點),我們只是簡單的用C替換M,根據性質4,C必定是黑色(這只能在m有兩個葉子節點時發生,因爲刪除的節點最多隻有一個非空兒子,如果紅色節點m的一側有一個黑色的非空葉子節點,而另一側有一個葉子節點,則兩側的黑色節點計數將不同,因此將違反性質5)。所以我們可以簡單的用它的黑色兒子替換它,並不會破壞性質3和性質4。通過被刪除節點的所有路徑只是少了一個紅色節點,這樣可以繼續保證性質5。
  2. 另一種簡單情況是M爲黑色,C爲紅色。如果只是去除這個黑色節點,用它的紅色兒子頂替上來的話,會破壞性質5,但是如果我們重繪它的兒子爲黑色,則曾經通過它的所有路徑將通過它的黑色兒子,這樣可以繼續保持性質5
  3. 複雜的情況是M和C都是黑色的。(這種情況下該結點的兩個兒子都是葉子結點,否則若其中一個兒子是黑色非葉子結點,另一個兒子是葉子結點,那麼從該結點通過非葉子結點兒子的路徑上的黑色結點數最小爲2,而從該結點到另一個葉子結點兒子的路徑上的黑色結點數爲1,違反了性質5)。

我們首先把要刪除的節點M替換爲它的兒子C,在將在新的位置上的C稱爲N,稱呼它的兄弟(它父親的另一個兒子)爲S。在下面的示意圖中,我們還是使用P稱呼N的父親,SL稱呼S的左兒子,SR稱呼S的右兒子。

如果N和它初始的父親是黑色,則刪除它的父親導致通過N的路徑都比不通過它的路徑少了一個黑色節點。因爲這違反了性質5,樹需要被重新平衡。有幾種情形需要考慮:

case1:N是新的根。

在這種情形下,刪除原節點後我們就做完了。我們從所有路徑去除了一個黑色節點,而新根是黑色的,所有性質都保持着。

case2: S是紅色。

在這種情形下我們在N的父親上做左旋轉,把紅色兄弟S轉換成N的祖父,我們接着對調N的父親和祖父的顏色。完成這兩個操作後,儘管所有路徑上黑色節點的數目沒有改變,但是我們刪除了一個黑色節點,此時通過原來刪除的節點的黑色路徑長度少1,所以我們需要接下去按case4、case5或case6來處理。
在這裏插入圖片描述

case3: N的父親、S和S的兒子都是黑色的。

在這種情形下,我們簡單的重繪S爲紅色。結果是通過S的所有路徑,它們就是以前不通過N的那些路徑,都少了一個黑色節點。因爲刪除N的初始的父親使通過N的所有路徑少了一個黑色節點,這使事情都平衡了起來。但是,通過P的所有路徑現在比不通過P的路徑少了一個黑色節點,所以仍然違反性質5。要修正這個問題,我們要從case2開始,在P上做重新平衡處理。

在這裏插入圖片描述

case4: S和S的兒子都是黑色,但是N的父親是紅色。

在這種情形下,我們簡單的交換N的兄弟和父親的顏色。這不影響不通過N的路徑的黑色節點的數目,但是它在通過N的路徑上對黑色節點數目增加了一,添補了在這些路徑上刪除的黑色節點。
在這裏插入圖片描述

case5: S是黑色,S的左兒子是紅色,S的右兒子是黑色,而N是它父親的左兒子。

在這種情形下我們在S上做右旋轉,這樣S的左兒子成爲S的父親和N的新兄弟。我們接着交換S和它的新父親的顏色。所有路徑仍有同樣數目的黑色節點,但是現在N有了一個黑色兄弟,他的右兒子是紅色的,所以我們進入了case6。N和它的父親都不受這個變換的影響。
在這裏插入圖片描述

case6: S是黑色,S的右兒子是紅色,而N是它父親的左兒子。

在這種情形下我們在N的父親上做左旋轉,這樣S成爲N的父親P和S的右兒子的父親。我們接着交換N的父親和S的顏色,並使S的右兒子爲黑色。子樹在它的根上的仍是同樣的顏色,所以性質3沒有被違反。現在通過N的路徑都增加了一個黑色節點,彌補了被刪除的節點,同時新祖父節點的顏色不變,所以通過N的路徑的黑色節點數目與刪除節點前保持不變。

此時,不通過N的路徑(變化之前通過P右子樹即通過S的左右子樹)則有兩種可能性:

  • 它通過N的新兄弟(以前S的左孩子)。那麼它以前和現在都必定通過P和S,而它們只是交換了顏色。所以路徑保持了同樣數目的黑色節點。
  • 它通過N的新叔父(以前/現在S的右孩子),S的右兒子SR。那麼它以前通過P、S和SR,現在通過S和SR。同樣變化前後通過了同樣數目的黑色節點。

所以在任何情況下,在這些路徑上的黑色節點數目都沒有改變。所以我們恢復了性質4。在示意圖中的白色節點可以是紅色或黑色,但是在變換前後都必須指定相同的顏色。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章