紅黑樹(red-black tree)

紅黑樹函數

  普通的二叉搜索樹高度若是較高時,一些集合操做可能不比鏈表上執行的快,而紅黑樹屬於「平衡」搜索樹的一種,能夠保證在最壞狀況下基本動態集合操做的時間複雜度爲O(lgn).spa

(一)紅黑樹的性質指針

  紅黑樹是一棵二叉搜索樹,在每一個結點上增長了一個存儲位來表示結點的顏色,能夠爲RED或者BLACK。經過一些約束能夠保證沒有一條路徑會比其餘路徑長出2倍,於是是近似於平衡的。搜索

 

紅黑樹的5個性質:
循環

1. 每一個結點或是紅色的,或是黑色的。
程序

2. 根結點是黑色的。im

3. 每一個葉節點(NIL)是黑色的。鏈表

4. 若是一個結點是紅色的,則它的兩個子結點都是黑色的。img

5. 對每一個結點,從該結點到其全部後代葉結點的簡單路徑上,均包含相同數目的黑色結點。紅黑樹

 

  爲了節省空間,使用一個哨兵T.nil來表示全部的NIL:全部的葉結點和根結點的父結點。

  黑高(black-height):定義從某個結點x出發(不含該結點)到達一個葉結點的任意一條簡單路徑上的黑色結點個數稱爲該結點的黑高,記爲bh(x).

             如圖爲一棵紅黑樹例子,根結點的父結點與葉結點用nil表示

 

  

(二)旋轉

  爲了實現紅黑樹的插入和刪除操做,這裏須要一種能保持二叉搜索樹性質的搜索樹局部操做:旋轉。

  如圖給出兩種旋轉:左旋和右旋。當在某個結點x上作左旋時,假設它的右孩子爲y而不是T.nil,即x能夠是右孩子不是T.nil結點的樹內任意結點。左旋以x到y的鏈爲「支軸」進行,它使y成爲該子樹新的根結點,x成爲y的左孩子,y的左孩子成爲x的右孩子。

下面是左旋僞代碼,假設x.right != T.nil

右旋與左旋代碼對稱,兩個操做都在O(1)時間內完成。

 

(三)插入

  一棵含n個結點的紅黑樹中插入一個新結點能夠在O(lgn)的時間內完成。爲了作到這一點,調用RB-INSERT(T , z)在紅黑樹中插入結點z,其中利用輔助程序RB-INSERT-FIXED來對結點進行從新着色並旋轉,以維持紅黑樹性質。

  這裏RB-INSERT與普通的二叉搜索樹插入比較類似,將新插入的結點標記爲紅色而後找到一個位置插入,而後在最後調用RB-INSERT-FIXUP來維護紅黑樹性質。

  代碼只討論了z的父親爲爺爺的左孩子的狀況,父親爲右孩子的狀況恰好相對。這種狀況又有3種可能:1. z的叔結點(爺爺的右孩子)爲紅色。2. z的叔結點爲黑色且z是一個右孩子。3. z的叔結點是黑色且z是左孩子。

1.

  直接變換顏色可讓指針z上移兩層

2和3.

  對於狀況2,直接對z執行z = z.p並對新的z左旋便可變成狀況3.對於狀況3,改變z的父結點和爺爺結點的顏色並對爺爺結點進行右旋便可。

  能夠證實整個過程沒有改變二叉搜索樹的性質並最終維護了紅黑樹的性質,RB-INSERT的運行時間爲O(lgn).

 

(四)刪除

  紅黑樹刪除的過程比較複雜,刪除一個節點須要O(lg n)的時間。

首先是輔助函數RB-TRANSPLANT , 用v結點替代u結點的位置並將u結點刪除。

 

 

注意第6行即便u是根結點也沒有問題,由於引入了nil結點。

下面是RB-DELETE函數,刪除掉z結點,並在最後調用RB-DELETE-FIXUP函數來保持紅黑樹性質。

  代碼中z爲將要刪除的結點,而後記錄y結點的蹤影,其中y結點可能破壞紅黑性質,由於過程當中移動了y的位置。刪除掉結點z後,y將會頂替z的位置。若是z只有一個子結點,則能夠直接刪除並由惟一的子結點頂上。若是z有2個子結點,則y是z的後繼,能夠在y的右子樹中一直向左找到最後一個結點便可,並知道y確定沒有左子結點。還要記錄y的子結點x,由於x將移到原來y的位置,而且可能也會致使紅黑性質的破壞。

  代碼第21行只在y-original-color爲black時候才調用FIXUP函數來回復紅黑性質,由於能夠看出刪除或移動一個紅色結點不會致使紅黑性質的破壞。而若是y是黑色的則會產生3個問題,均可以經過調用FIXUP函數進行補救。第一, 若是y原來是根結點,而y的一個紅色孩子成爲了新的根結點,就會違反紅黑樹的性質2.  第二, 若是x和x.p是紅色的,就違反了性質4.  第三, 在樹中移動y將致使先前包含y的任何簡單路徑上的黑色結點個數減小1,所以y的任何祖先都不知足性質5.

  這時候針對第三個問題的策略是將原先y的黑色向下推給x,即假想x的黑色性質加1.咱們只須要假想而不須要真正修改x.color.若是x自己是黑色,則變成黑黑,若是原先是紅色,則變成紅黑。這時候須要將x多出來的那重黑色通過適當處理消掉,從而恢復紅黑樹的性質。

  代碼執行一個while循環,目標是將多出的黑色性質往上推,直到遇到x自己爲紅色的,即假想的紅黑結點,這樣就能夠直接將x.color置爲黑色解決;

或者x最終指向根結點,也能夠簡單的將額外的黑色性質移除;或者能夠執行適當的旋轉和從新着色而退出循環完成目標。

  代碼只給出x爲左孩子的狀況,另外一種狀況與這種恰好相對,能夠經過left與right互換獲得。而x爲左孩子又能夠分爲4種狀況,而且其中的一些狀況能夠經過一些操做轉換。4種狀況在代碼中已經標出。

1.x的兄弟結點w是紅色的。

2.x的兄弟結點w是黑色的,並且w的2個孩子都是黑色的。

3.x的兄弟結點w是黑色的,w的左孩子是紅色的,又孩子是黑色的。

4.x的兄弟結點w是黑色的,且w的右孩子是紅色的。

  圖中分別表示4種狀況進行的操做,其中加黑的表示黑色結點,深陰影的爲紅色結點,淺陰影的結點顏色能夠爲黑色或者紅色。

  結合代碼與圖便可理解每一種操做,注意狀況3會轉化爲狀況4,而狀況4在將x設置爲根後會跳出循環。

相關文章
相關標籤/搜索