紅黑樹——一個自平衡的二叉搜索樹

普通的二叉搜索樹在最壞的情況下,可能退化成一個鏈表。而又因為二叉搜索樹的所有操作的性能(添加,刪除,查找等),與二叉搜索樹的高度有關。在最壞的情況下,二叉搜索樹的高度和元素個數相同,此時二叉搜索樹的效率降為了O(n)級別。

所以為了防止我們的二叉搜索樹退化成一個鏈表,就產生了平衡二叉樹平衡二叉樹可以保證它的左右兩個子樹的高度差不會超過1。平衡二叉樹有很多實現,一個經典實現就是紅黑樹

紅黑樹

在紅黑樹中將樹中的節點劃分為兩種狀態,分別用黑色和紅色來表示。

紅黑樹為了保證自己能夠平衡子樹,所以制訂以下五個規則:

1、每個節點必須有顏色,要么黑色,要么紅色,沒有別的顏色。
2、根節點必須是黑色
3、所有的空節點(nil節點)都認為是黑色節點。
4、紅色的節點不能連續,即一個紅色的節點,它的父節點和子節點不能也是紅色的,
5、無論從哪一個節點起始,到它每個葉子節點的路徑中,黑色節點數量必須相同。

在對紅黑樹進行添加、刪除等操作之后,必須使紅黑樹符合這5個規則。
那么問題來了,在添加刪除操作之后,樹中節點的數量都變了,是怎么保證整個樹滿足上述這些規則呢?
這里涉及到3種操作,變色左旋右旋。通過這個三種操作,在增刪節點之后調整樹的形狀結構,使它滿足上述5個規則。這也是紅黑樹能保持平衡的原因。

變色操作我們在下文的添加、刪除節點的實際操作中,再進行在描述。

先來說一下左右旋。

左旋

左旋是指以某節點為支點,進行逆時針旋轉。如下圖,是以2為支點進行的左旋:
圖1.png

文字描述一下就是,2的右孩子節點4,變為了2的父節點,2由父節點變為4的左孩子。同時,4原來的左孩子變為2的右孩子。

右旋

右旋與左旋相反,即以某節點為支點進行順時針旋轉。同樣,我們看下圖,是以5為支點進行的右旋:


圖2.png

文字描述同樣反過來,5的左孩子節點3,變為5的父節點,5由父節點變為3的右孩子。3原來的右孩子變為5的左孩子。

插入新節點

首先是在樹中找到新節點正確的位置,尋找位置的過程與普通的二叉搜索樹相同,只是將新插入的節點默認為紅色節點。為什么默認為紅色?因為如果你將新節點默認為黑色,則插入后肯定會打破原本符合規則的紅黑樹(上述第5條規則)。但是,如果你將新節點定為紅色,則有可能不用任何操作就符合紅黑樹規則,如下圖,當新插入的紅色節點,它的父親節點為黑色時候,此時已經滿足紅黑樹規則了。所以用紅色比黑色好。

圖3.png

如果很不巧,新插入的節點的父親節點也為紅色,因為紅色節點不能連續,所以我們需要調整紅黑樹的結構使其滿足規則。在調整的過程中我們會遇到3種需要處理的情況,我們來一一進行說明。

情況1:

圖4.png

插入新節點40,此時它的父節點為紅色,并且它的叔叔節點(即51)也為紅色。此時我們需要進行變色操作。將該節點的父親節點、叔叔節點都變為黑色,祖父節點變為紅色

圖5.png

此時上圖已經滿足紅黑樹的規則。但有的時候我們經過了變色操作后,仍不滿足紅黑樹的規則,會遇到下面的情況。
情況2:

圖9.png

如圖,我們插入新的節點53,在按情況1的操作變色后,變成了這樣:

圖10.png

此時,49與44為兩個連續的紅色,顯然不符合規則。此時的操作為:我們將49看做當前節點,將當前節點的父節點44變為黑色,祖父節點35置為紅色,以祖父節點為支點進行左旋
圖11.png

此時情況2就處理完成了。

最后我們說一下情況3的情景,如下圖:

圖6.png

我們向樹中插入新節點37,在按情況1的操作變色后,變成了這樣:

情況3:

圖7.png

此時,49與44為兩個連續的紅色,顯然不符合規則。而我們只需以49為支點,進行一次右旋,就變成了情況2。如下圖。
圖8.png

再按情況2進行一次操作就符合規則了。

3種情況我們說明完了,但是你可能還會有這樣的疑問,什么時候進行左旋,什么時候進行右旋;什么時候以父節點為支點旋轉,什么時候又以祖父節點為支點旋轉?

那么我們可以總結一下,當遇到連續的紅色節點應該怎么辦:當前節點我們叫它X,如果X相對于父節點的左右位置和父節點相對于祖父節點的左右位置相同,此時,就以祖父節點為支點,進行反向旋轉。例如:X為父節點的左孩子,X的父節點同樣也是其祖父節點的左孩子,此時以祖父節點為支點進行右旋;
如果X相對于父節點的左右位置和父節點相對于祖父節點的左右位置不同,則以X的父節點為支點,進行旋轉,旋轉方向與X相對于父節點左右位置相反。例如:X為其父節點的左孩子,X的父節點為祖父節點的右孩子,此時以X的父節點為支點進行一次右旋。

刪除節點

在紅黑樹中刪除節點,肯定要涉及到要刪的這個節點是紅色的還是黑色的。刪除紅色比較簡單,我們先說一下刪除紅色節點。

刪除節點要考慮這個節點所處的位置,所以我們羅列一下紅色的節點所有可能的位置情況。

  • 它是一個葉子節點。
  • 它既有左子樹也有右子樹。

你可能會發現為什么少了一種情況?它不能只有左子樹或者只有右子樹嗎?我們可以看下圖:


圖12.png

很明顯,這四種情況都不符合紅黑樹的規則,所以根本不會出現這種情況。

而對于既有左子樹也有右子樹的情況。我們可以先和普通的二叉搜索樹的刪除操作一樣,將它與前驅或者后繼交換一下。它就又變成第一種情況——成為了一個葉子節點。所以我們只需考慮當它是葉子節點的情況。

圖13.png

很簡單,直接刪除紅色葉子節點。

接下來我們看一下當要刪除的節點是黑色的時候應該怎么辦。
同樣我們列一下節點位置可能的情況:

  • 它是一個葉子節點。
  • 它只有左子樹,或只有右子樹。
  • 它既有左子樹也有右子樹。

第三種情況和刪除紅色節點時的處理方法一樣,可以轉換成第一種或第二種情況,所以我們只關心前兩種情況。

當要刪除的黑色節點只有一個子樹時:

圖14.png

它的左孩子或者右孩子一定是紅色的,因為如果是黑色的就不符合紅黑樹的規則了。
操作方法為:我們只需要將它的子節點變黑,然后代替它的位置就完成了。
圖15.png

最后我們看一下最難處理的一種情況。

要刪除的黑色節點是葉子節點時:
情況1:待刪除黑色節點20,它的兄弟節點為紅色。

圖16.png

此時的操作為,將兄弟節點和父節點顏色交換,即父親變紅,兄弟變黑。然后以父節點為支點進行左旋。(旋轉方向同樣是與待刪除節點的左右位置相同)
圖17.png

此時會變成了下述的情況4,再按情況4進行操作就可以了。
情況2:待刪除黑色節點20,它的兄弟節點為黑色,并且它擁有紅色的遠侄子節點,近侄子節點有沒有都可以。(侄子節點即兄弟節點的子節點,遠侄子節點就是,當前節點如果是其父節點的左孩子,那么它的遠侄子節點就是兄弟節點的右孩子,近侄子同理)

圖18.png

操作方法為:將遠侄子節點變黑,兄弟節點與父親節點互換顏色,最后以父節點為支點進行左旋。(為什么是左旋?因為待刪除的20是左孩子,我們要將左子樹長度拉長,將它沉下來,使它變成多余的節點好刪除它,如果它是右孩子,則進行右旋)
操作后如下圖就完成了。

圖19.png


情況3:待刪除黑色節點20,它的兄弟節點為黑色,但它沒有紅色的遠侄子節點(即nil點,記住,nil點算黑色),只有紅色的近侄子節點。

圖20.png

操作方法為:將兄弟節點與近侄子節點交換顏色,再以兄弟節點進行右旋。(旋轉方向很好記,因為此處旋轉的目的是為了創造遠侄子,近侄子節點是左節點,所以就只能右旋了,如果近侄子是右節點則進行左旋。)

操作后如下圖:


圖21.png

此時有了紅色的遠侄子,就滿足了情況2,再按情況2進行一次操作就完成了。

情況4:待刪除黑色節點20,它的兄弟節點為黑色,遠侄子、近侄子節點都沒有。(即兩個nil節點,nil節點算黑色)

圖24.png

操作方法為:將兄弟節點變為紅色,同時最關鍵的是,將當前節點20的父節點50,看做當前節點,繼續遞歸的進行這四種情況的判斷,直到當前節點為紅色,或者當前節點是根節點才停止。最后將當前節點變為黑色!!

我們將上圖紅黑樹按流程演示一下:
第一步按情況4操作,將55變紅。并將父節點50看做當前節點,繼續操作。


圖25.png

此時,當前節點50為黑色,兄弟節點68也為黑色,且它的兩個侄子65和70都為黑色,所以仍符合情況4。將68變紅,并將父節點61看做當前節點,繼續操作。
圖26.png

此時當前節點61為紅色,滿足停止遞歸條件,將61變為黑色,停止。整個操作完成。
圖27.png

此時有關紅黑樹的知識就說完了。
以上所有內容都為自己查閱資料學習理解之后手敲的。盡量得采用通俗易懂的描述和解釋讓讀者更明白。27張圖都是自己親自畫的,花費了四天才寫完,如果覺得寫的還可以,麻煩點亮喜歡支持一下,如果還是不懂,可以下方留言QQ等聯系方式,我親自告訴你。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容