紅黑樹-插入篇

出處:http://www.cnblogs.com/sandy2013/p/3270999.html

紅黑樹插入操作比較複雜,特地從網上整理了一下,下面這兩種解釋結合起來看,就可以輕鬆理解紅黑樹的插入操作了。

原博文的地址爲:http://www.cnblogs.com/xuqiang/archive/2011/05/16/2047001.html

http://blog.csdn.net/hackbuteer1/article/details/7740956

由於STL中的關聯式容器默認的底層實現都是紅黑樹,因此紅黑樹對於後續學習STL源碼還是很重要的,有必要掌握紅黑樹的實現原理和源碼實現。
     紅黑樹是AVL樹的變種,紅黑樹通過一些着色法則確保沒有一條路徑會比其它路徑長出兩倍,因而達到接近平衡的目的。所謂紅黑樹,不僅是一個二叉搜索樹,而且必須滿足一下規則:
     1、每個節點不是紅色就是黑色。
     2、根節點爲黑色。
     3、如果節點
爲紅色,其子節點必須爲黑色
     4、任意一個節點到到NULL(樹尾端)的任何路徑,所含之黑色節點數必須相同。

上面的這些約束保證了這個樹大致上是平衡的,這也決定了紅黑樹的插入、刪除、查詢等操作是比較快速的。 根據規則4,新增節點必須爲紅色;根據規則3,新增節點之父節點必須爲黑色。當新節點根據二叉搜索樹的規則到達其插入點時,卻未能符合上述條件時,就必須調整顏色並旋轉樹形,如下圖:

假設我們爲上圖分別插入節點3、8、35、75,根據二叉搜索樹的規則,插入這四個節點後,我們會發現它們都破壞了紅黑樹的規則,因此我們必須調整樹形,也就是旋轉樹形並改變節點的顏色。

二、紅黑樹上結點的插入

      在討論紅黑樹的插入操作之前必須要明白,任何一個即將插入的新結點的初始顏色都爲紅色。這一點很容易理解,因爲插入黑點會增加某條路徑上黑結點的數目,從而導致整棵樹黑高度的不平衡。但如果新結點的父結點爲紅色時(如下圖所示),將會違反紅黑樹的性質:一條路徑上不能出現相鄰的兩個紅色結點。這時就需要通過一系列操作來使紅黑樹保持平衡。

      爲了清楚地表示插入操作以下在結點中使用“新”字表示一個新插入的結點;使用“父”字表示新插入點的父結點;使用“叔”字表示“父”結點的兄弟結點;使用“祖”字表示“父”結點的父結點。插入操作分爲以下幾種情況:
1、黑父
     如下圖所示,如果新節點的父結點爲黑色結點,那麼插入一個紅點將不會影響紅黑樹的平衡,此時插入操作完成。紅黑樹比AVL樹優秀的地方之一在於黑父的情況比較常見,從而使紅黑樹需要旋轉的機率相對AVL樹來說會少一些。

2、紅父
     如果新節點的父結點爲紅色,這時就需要進行一系列操作以保證整棵樹紅黑性質。如下圖所示,由於父結點爲紅色,此時可以判定,祖父結點必定爲黑色。這時需要根據叔父結點的顏色來決定做什麼樣的操作。青色結點表示顏色未知。由於有可能需要根結點到新點的路徑上進行多次旋轉操作,而每次進行不平衡判斷的起始點(我們可將其視爲新點)都不一樣。所以我們在此使用一個藍色箭頭指向這個起始點,並稱之爲判定點。

2.1 紅叔
當叔父結點爲紅色時,如下圖所示,無需進行旋轉操作,只要將父和叔結點變爲黑色,將祖父結點變爲紅色即可。但由於祖父結點的父結點有可能爲紅色,從而違反紅黑樹性質。此時必須將祖父結點作爲新的判定點繼續向上(迭代)進行平衡操作。

需要注意的是,無論“父節點”在“叔節點”的左邊還是右邊,無論“新節點”是“父節點”的左孩子還是右孩子,它們的操作都是完全一樣的(其實這種情況包括4種,只需調整顏色,不需要旋轉樹形)。
2.2 黑叔
當叔父結點爲黑色時,需要進行旋轉,以下圖示了所有的旋轉可能:
Case 1:

Case 2:

Case 3:

Case 4:

      可以觀察到,當旋轉完成後,新的旋轉根全部爲黑色,此時不需要再向上回溯進行平衡操作,插入操作完成。需要注意,上面四張圖的“叔”、“1”、“2”、“3”結點有可能爲黑哨兵結點。

幫助理解插入操作:
通過上面的操作生成的只有一個節點的樹,滿足1-5條性質,顯然該樹是紅黑樹。

 

 

 特殊情況考慮完成之後,下面假設又開始添加節點,我們面對的第一個問題是新增加的節點是標記成紅色還是黑色?顯然無論是新插入的節點是黑色或者是紅色,紅黑樹限制1,2,3一定是滿足的,那麼如果將新插入的節點標識成黑色的話,可能違反5,但是如果將新插入的節點標識成紅色,肯能違反4,看似好像是兩個是類似的。

 

但是考慮這樣的一種情況:如果新插入的節點標識成紅色,並且新插入的節點的父節點是黑色,那麼是違反性質4的,也就是說是不需要重新調整紅黑樹的。

 

 

 

但是如果標識成黑色的話,那麼是一定會違反性質5,好的,我們還是選擇將插入的節點標識成紅色吧,至少運氣好的話,就不需要重新調整紅黑樹了。 

 

 確定了新插入的節點的顏色之後,現在開始具體的實現插入操作,由於紅黑樹實際上也是一種二叉查找樹,那麼新插入的頂點一定是在紅黑樹的最低端,我們忽略掉這個查找節點的過程,這裏僅僅關心插入節點之後如何調整紅黑樹。數學上的常用方法:分類討論

 

case 1. 如果插入的節點是根節點,也就是說初始的紅黑樹爲空,這是最簡單的情況,直接將該節點標識成黑色即可。

 

 

case 2. 如果新插入的節點不是紅黑樹的根節點,如果新插入的節點的父節點是黑色的話,那麼紅黑樹是不需要調整的

 

 

 

 

 

case 3. 如果新插入的節點的父節點是紅色的話,顯然這裏違反了紅黑樹中不能存在父節點和子節點同時爲紅色的性質,。

 

 

 

於是需要調整,我們的調整的目標是在不違反紅黑樹性質(或者是可調整)如何將兩個相鄰的紅色節點分隔開來,顯然最終的結果是我們需要將新插入的節點的父節點更改成黑色(新插入節點是如法作出調整的,實現將兩個紅色節點分割開的,除非將該節點標識爲黑色,但是這會增加黑高度),但是如果是單純的修改父節點爲黑色的話,那麼將會違背黑色頂點數目的性質,直接修改是行不通,那麼能否通過交換兩個兩個節點達到目的呢?

 

顯然新插入的節點的祖父節點一定是黑色的,那麼是否能夠通過交換父節點和祖父節點的紅黑性質來達到目的呢?顯然這可能違反將新插入節點的叔叔子樹的紅黑樹性質破壞掉。但是如果叔叔節點是紅色的話,問題似乎變得很簡單了。 

 

 

 

我們僅僅需要將主父節點改成紅色,同時將父節點和叔叔節點改成黑色即可。

 

 

 

但是這將引入新的問題, 顯然我們將G節點表示成紅色之後,那麼G節點和G的父節點是可能違反紅黑性質的,爲了解決這個問題,這裏使用尾遞歸的形式來對節點G進行調整。

 

 

一種情況已經解決。下面將是更加艱鉅的任務,如果叔叔節點是黑色的,該如何是好?

 

 case 4:我們來看看還剩下的就是這種情況了,P爲紅色,U爲黑色,G爲黑色,怎麼解決?對了,到這裏是否忘了我們的最終目的是什麼?

 

 在不違反紅黑樹性質(或者是可調整)如何將兩個相鄰的紅色節點分隔開來. 

 

 

 

 

 

直接將P節點修改成黑色是不行的,這將增加G-P-U路徑上的黑高度, 沒有思路,好的,來回頭看看case 3的情況,畢竟已經解決了一種情況,case 3中我們修改了節點G的顏色,爲什麼能夠修改,顯然是說G是最頂點(輩份最高)的節點,最頂點的節點的顏色可以是紅色(重新調整)或者是黑色。

 

那如果我們呢將P節點提升至現在G的位置呢(通過樹的旋轉)?

 

 

 

現在可以將P的顏色標識成黑色,但是會破壞P-G-U的黑路徑,運用一下交換的思想吧,交換P和G的顏色即可。

 

現在基本上已經解決了紅黑樹中如果叔叔是黑色的情況,剩下的工作就是分析旋轉方向,根據節點P和N是左孩子還是右孩子進行相應旋轉。

 

這是case 4情況:

 

 

 

或者是:

 

 

 

 

這樣將P和U不再同一條直線的情景轉換成在統一條直線上的情況,case 5我們處理在同一條直線上的情況:

 

case 5:

 

 

 

或者是:

 

 

 

 

紅黑樹的插入的所有情況分析完了,

 


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