紅黑樹知識全面詳解之節點插入

2021-09-01 20:26:02 字數 4330 閱讀 6368

將乙個節點插入到紅黑樹中,需要執行哪些步驟呢?首先,將紅黑樹當作一顆二叉查詢樹,將節點插入;然後,將節點著色為紅色;最後,通過旋轉和重新著色等方法來修正該樹,使之重新成為一顆紅黑樹。詳細描述如下:

第一步: 將紅黑樹當作一顆二叉查詢樹,將節點插入。

紅黑樹本身就是一顆二叉查詢樹,將節點插入後,該樹仍然是一顆二叉查詢樹。也就意味著,樹的鍵值仍然是有序的。此外,無論是左旋還是右旋,若旋轉之前這棵樹是二叉查詢樹,旋轉之後它一定還是二叉查詢樹。這也就意味著,任何的旋轉和重新著色操作,都不會改變它仍然是一顆二叉查詢樹的事實。

好吧?那接下來,我們就來想方設法的旋轉以及重新著色,使這顆樹重新成為紅黑樹!

第二步:將插入的節點著色為"紅色"。

為什麼著色成紅色,而不是黑色呢?為什麼呢?在回答之前,我們需要重新溫習一下紅黑樹的特性:

(1) 每個節點或者是黑色,或者是紅色。

(2) 根節點是黑色。

(3) 每個葉子節點是黑色。 [注意:這裡葉子節點,是指為空的葉子節點!]

(4) 如果乙個節點是紅色的,則它的子節點必須是黑色的。

(5) 從乙個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點。

將插入的節點著色為紅色,不會違背"特性(5)"!少違背一條特性,就意味著我們需要處理的情況越少。接下來,就要努力的讓這棵樹滿足其它性質即可;滿足了的話,它就又是一顆紅黑樹了。

第三步: 通過一系列的旋轉或著色等操作,使之重新成為一顆紅黑樹。

第二步中,將插入節點著色為"紅色"之後,不會違背"特性(5)"。那它到底會違背哪些特性呢?

對於"特性(1)",顯然不會違背了。因為我們已經將它塗成紅色了。

對於"特性(2)",顯然也不會違背。在第一步中,我們是將紅黑樹當作二叉查詢樹,然後執行的插入操作。而根據二叉查詢數的特點,插入操作不會改變根節點。所以,根節點仍然是黑色。

對於"特性(3)",顯然不會違背了。這裡的葉子節點是指的空葉子節點,插入非空節點並不會對它們造成影響。

對於"特性(4)",是有可能違背的!

那接下來,想辦法使之"滿足特性(4)",就可以將樹重新構造成紅黑樹了。

根據被插入節點的父節點的情況,可以將"當節點z被著色為紅色節點,並插入二叉樹"劃分為三種情況來處理。

① 情況說明:被插入的節點是根節點。

處理方法:直接把此節點塗為黑色。

② 情況說明:被插入的節點的父節點是黑色。

處理方法:什麼也不需要做。節點被插入後,仍然是紅黑樹。

③ 情況說明:被插入的節點的父節點是紅色。

處理方法:那麼,該情況與紅黑樹的「特性(5)」相衝突。這種情況下,被插入節點是一定存在非空祖父節點的;進一步的講,被插入節點也一定存在叔叔節點(即使叔叔節點為空,我們也視之為存在,空節點本身就是黑色節點)。理解這點之後,我們依據"叔叔節點的情況",將這種情況進一步劃分為3種情況(case)。

現象說明

處理策略

case 1

當前節點的父節點是紅色,且當前節點的祖父節點的另乙個子節點(叔叔節點)也是紅色。

(01) 將「父節點」設為黑色。

(02) 將「叔叔節點」設為黑色。

(03) 將「祖父節點」設為「紅色」。

(04) 將「祖父節點」設為「當前節點」(紅色節點);即,之後繼續對「當前節點」進行操作。

case 2

當前節點的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的右孩子

(01) 將「父節點」作為「新的當前節點」。

(02) 以「新的當前節點」為支點進行左旋。

case 3

當前節點的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的左孩子

(01) 將「父節點」設為「黑色」。

(02) 將「祖父節點」設為「紅色」。

(03) 以「祖父節點」為支點進行右旋。

1. (case 1)叔叔是紅色

1.1 現象說明

當前節點(即,被插入節點)的父節點是紅色,且當前節點的祖父節點的另乙個子節點(叔叔節點)也是紅色。

1.2 處理策略

(01) 將「父節點」設為黑色。

(02) 將「叔叔節點」設為黑色。

(03) 將「祖父節點」設為「紅色」。

(04) 將「祖父節點」設為「當前節點」(紅色節點);即,之後繼續對「當前節點」進行操作。

「當前節點」和「父節點」都是紅色,違背「特性(4)」。所以,將「父節點」設定「黑色」以解決這個問題。

但是,將「父節點」由「紅色」變成「黑色」之後,違背了「特性(5)」:因為,包含「父節點」的分支的黑色節點的總數增加了1。解決這個問題的辦法是:將「祖父節點」由「黑色」變成紅色,同時,將「叔叔節點」由「紅色」變成「黑色」。關於這裡,說明幾點:

第一,為什麼「祖父節點」之前是黑色?這個應該很容易想明白,因為在變換操作之前,該樹是紅黑樹,「父節點」是紅色,那麼「祖父節點」一定是黑色。 第二,為什麼將「祖父節點」由「黑色」變成紅色,同時,將「叔叔節點」由「紅色」變成「黑色」;能解決「包含『父節點』的分支的黑色節點的總數增加了1」的問題。這個道理也很簡單。「包含『父節點』的分支的黑色節點的總數增加了1」 同時也意味著 「包含『祖父節點』的分支的黑色節點的總數增加了1」,既然這樣,我們通過將「祖父節點」由「黑色」變成「紅色」以解決「包含『祖父節點』的分支的黑色節點的總數增加了1」的問題; 但是,這樣處理之後又會引起另乙個問題「包含『叔叔』節點的分支的黑色節點的總數減少了1」,現在我們已知「叔叔節點」是「紅色」,將「叔叔節點」設為「黑色」就能解決這個問題。 所以,將「祖父節點」由「黑色」變成紅色,同時,將「叔叔節點」由「紅色」變成「黑色」;就解決了該問題。

按照上面的步驟處理之後:當前節點、父節點、叔叔節點之間都不會違背紅黑樹特性,但祖父節點卻不一定。若此時,祖父節點是根節點,直接將祖父節點設為「黑色」,那就完全解決這個問題了;若祖父節點不是根節點,那我們需要將「祖父節點」設為「新的當前節點」,接著對「新的當前節點」進行分析。

2.(case 2)叔叔是黑色,且當前節點是右孩子

2.1 現象說明

當前節點(即,被插入節點)的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的右孩子

2.2 處理策略

(01) 將「父節點」作為「新的當前節點」。

(02) 以「新的當前節點」為支點進行左旋。

首先,將「父節點」作為「新的當前節點」;接著,以「新的當前節點」為支點進行左旋。 為了便於理解,我們先說明第(02)步,再說明第(01)步;為了便於說明,我們設定「父節點」的代號為f(father),「當前節點」的代號為s(son)。

為什麼要「以f為支點進行左旋」呢?根據已知條件可知:s是f的右孩子。而之前我們說過,我們處理紅黑樹的核心思想:將紅色的節點移到根節點;然後,將根節點設為黑色。既然是「將紅色的節點移到根節點」,那就是說要不斷的將破壞紅黑樹特性的紅色節點上移(即向根方向移動)。 而s又是乙個右孩子,因此,我們可以通過「左旋」來將s上移! 

按照上面的步驟(以f為支點進行左旋)處理之後:若s變成了根節點,那麼直接將其設為「黑色」,就完全解決問題了;若s不是根節點,那我們需要執行步驟(01),即「將f設為『新的當前節點』」。那為什麼不繼續以s為新的當前節點繼續處理,而需要以f為新的當前節點來進行處理呢?這是因為「左旋」之後,f變成了s的「子節點」,即s變成了f的父節點;而我們處理問題的時候,需要從下至上(由葉到根)方向進行處理;也就是說,必須先解決「孩子」的問題,再解決「父親」的問題;所以,我們執行步驟(01):將「父節點」作為「新的當前節點」。

3. (case 3)叔叔是黑色,且當前節點是左孩子

3.1 現象說明

當前節點(即,被插入節點)的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的左孩子

3.2 處理策略

(01) 將「父節點」設為「黑色」。

(02) 將「祖父節點」設為「紅色」。

(03) 以「祖父節點」為支點進行右旋。

下面談談為什麼要這樣處理。(建議理解的時候,通過下面的圖進行對比)

為了便於說明,我們設定「當前節點」為s(original son),「兄弟節點」為b(brother),「叔叔節點」為u(uncle),「父節點」為f(father),祖父節點為g(grand-father)。

s和f都是紅色,違背了紅黑樹的「特性(4)」,我們可以將f由「紅色」變為「黑色」,就解決了「違背『特性(4)』」的問題;但卻引起了其它問題:違背特性(5),因為將f由紅色改為黑色之後,所有經過f的分支的黑色節點的個數增加了1。那我們如何解決「所有經過f的分支的黑色節點的個數增加了1」的問題呢? 我們可以通過「將g由黑色變成紅色」,同時「以g為支點進行右旋」來解決。

紅黑樹(插入)

紅黑樹的插入操作相對刪除操作比較簡單。紅黑樹要滿足 任一節點至null的任何路徑,所含黑節點數必須相同。所以,為了滿足此性質,插入節點應該為紅色。如果插入節點的父親為黑色,則不需要進行調整,若為紅色,有三種情況需要討論。1.父節點為紅色,叔節點為紅色 對於這種情況,同時改變父 叔節點顏色為黑色,並將...

紅黑樹插入

一 什麼是紅黑樹 紅黑樹 red black tree 是一種自平衡二叉查詢樹,是在電腦科學中用到的一種資料結構,典型的用途是實現關聯陣列。紅黑樹是一棵二叉搜尋樹,它在每個結點上增加了乙個儲存位來表示結點的顏色,可以是red或black。一棵紅黑樹是滿足下面紅黑性質的二叉搜尋樹 1 每乙個結點或是紅...

紅黑樹 插入

一 滿足下面幾個條件的二叉搜尋樹,稱為紅黑樹 1.任何乙個節點都被著色 紅色或是黑色。2.根節點是黑色的。3.所有的nil節點都看成黑色 nil節點是就是乙個假想的或是無實在意義的節點,所有應該指向null的指標,都看成指向了nil節點。包括葉節點的子節點指標或是根節點的父指標 4.如果乙個節點是紅...