概述:R-B Tree,,又稱為“紅黑樹”。本文參考了《算法導(dǎo)論》中紅黑樹相關(guān)知識,,加之自己的理解,,然后以圖文的形式對紅黑樹進(jìn)行說明。本文的主要內(nèi)容包括:紅黑樹的特性,,紅黑樹的時(shí)間復(fù)雜度和它的證明,,紅黑樹的左旋、右旋,、插入,、刪除等操作。 請尊重版權(quán),,轉(zhuǎn)載注明出處:http://www.cnblogs.com/skywang12345/p/3245399.html
1 R-B Tree簡介 R-B Tree,,全稱是Red-Black Tree,又稱為“紅黑樹”,,它一種特殊的二叉查找樹,。紅黑樹的每個(gè)節(jié)點(diǎn)上都有存儲(chǔ)位表示節(jié)點(diǎn)的顏色,可以是紅(Red)或黑(Black),。 紅黑樹的特性: 注意: 紅黑樹示意圖如下:
紅黑樹的應(yīng)用比較廣泛,,主要是用它來存儲(chǔ)有序的數(shù)據(jù),,它的時(shí)間復(fù)雜度是O(lgn),效率非常之高,。 這里大致介紹下,,紅黑樹和AVL樹的差異。AVL樹也是特殊的二叉樹,,它的特性是“任何節(jié)點(diǎn)的左右子樹的高度之差不超過1”,。基本上,,用到紅黑樹的地方都可以用AVL樹(自平衡二叉查找樹)去替換,。但是一般情況下,在執(zhí)行添加,、刪除節(jié)點(diǎn)時(shí),,AVL樹比紅黑樹執(zhí)行的操作更多一些,效率更低一些,;而且紅黑樹也是相對平衡的二叉樹(從一個(gè)節(jié)點(diǎn)到該節(jié)點(diǎn)的子孫節(jié)點(diǎn)的所有路徑上包含相同數(shù)目的黑節(jié)點(diǎn)),。因此,紅黑樹的效率會(huì)高更一點(diǎn),。
2 R-B Tree時(shí)間復(fù)雜度 紅黑樹的時(shí)間復(fù)雜度為: O(lgn) 定理:一棵含有n個(gè)節(jié)點(diǎn)的紅黑樹的高度至多為2log(n+1). 證明: 從某個(gè)節(jié)點(diǎn)x出發(fā)(不包括該節(jié)點(diǎn))到達(dá)一個(gè)葉節(jié)點(diǎn)的任意一條路徑上,,黑色節(jié)點(diǎn)的個(gè)數(shù)稱為該節(jié)點(diǎn)的黑高度,記為bh(x),。 到這里,我們將需要證明的定理已經(jīng)由
(01) 當(dāng)樹的高度h=0時(shí), (02) 當(dāng)h>0,且樹的高度為 h-1 時(shí),,它包含的節(jié)點(diǎn)個(gè)數(shù)至少為 2^{bh(x)-1}-1,。這個(gè)是根據(jù)(01)推斷出來的! 下面,,由樹的高度為 h-1 的已知條件推出“樹的高度為 h 時(shí),,它所包含的節(jié)點(diǎn)樹為 2^bh(x)-1”。 當(dāng)樹的高度為 h 時(shí),, 所以,,節(jié)點(diǎn)x所包含的節(jié)點(diǎn)至少為 ( 2^{bh(x)-1}-1 ) + ( 2^{bh(x)-1}-1 ) + 1 = 2^{bh(x)-1},。即節(jié)點(diǎn)x所包含的節(jié)點(diǎn)至少為 2^{bh(x)-1} ,。 由(01),、(02)得出,"高度為h的紅黑樹,,它的包含的內(nèi)節(jié)點(diǎn)個(gè)數(shù)至少為 2^bh(x)-1個(gè)",。
3 R-B Tree基本操作 R-B Tree的基本操作是添加,、刪除。 添加和刪除操作,,都會(huì)用到兩個(gè)基本的方法:左旋 和 右旋,,統(tǒng)稱為旋轉(zhuǎn)。旋轉(zhuǎn)是為了保持紅黑樹的特性而提供的輔助方法,,因?yàn)楫?dāng)我們進(jìn)行添加,、刪除節(jié)點(diǎn)時(shí),可能改變紅黑樹的特性(例如,,刪除一個(gè)黑色節(jié)點(diǎn)之后,,就不滿足“從一個(gè)節(jié)點(diǎn)到該節(jié)點(diǎn)的子孫節(jié)點(diǎn)的所有路徑上包含相同數(shù)目的黑節(jié)點(diǎn)”這個(gè)特性);這里,,我們就需要旋轉(zhuǎn)方法的輔助來讓樹保持紅黑樹的特性,。
3.1 左旋上面是《算法導(dǎo)論》中左旋的示意圖。 LEFT-ROTATE(T, x) 01 y ← right[x] // 前提:這里假設(shè)x的右孩子為y。下面開始正式操作 02 right[x] ← left[y] // 將 “y的左孩子” 設(shè)為 “x的右孩子”,,即 將β設(shè)為x的右孩子 03 p[left[y]] ← x // 將 “x” 設(shè)為 “y的左孩子的父親”,,即 將β的父親設(shè)為x 04 p[y] ← p[x] // 將 “x的父親” 設(shè)為 “y的父親” 05 if p[x] = nil[T] 06 then root[T] ← y // 情況1:如果 “x的父親” 是空節(jié)點(diǎn),則將y設(shè)為根節(jié)點(diǎn) 07 else if x = left[p[x]] 08 then left[p[x]] ← y // 情況2:如果 x是它父節(jié)點(diǎn)的左孩子,,則將y設(shè)為“x的父節(jié)點(diǎn)的左孩子” 09 else right[p[x]] ← y // 情況3:(x是它父節(jié)點(diǎn)的右孩子) 將y設(shè)為“x的父節(jié)點(diǎn)的右孩子” 10 left[y] ← x // 將 “x” 設(shè)為 “y的左孩子” 11 p[x] ← y // 將 “x的父節(jié)點(diǎn)” 設(shè)為 “y” 理解上面的代碼之后,,下面以一個(gè)更鮮明的圖對左旋轉(zhuǎn)進(jìn)行說明。理解左旋之后,,下面的推理應(yīng)該非常簡單,,這里就不過多說明。
3.2 右旋右旋和左旋是相對的,,原理類似,。理解左旋后,右旋也很容易理解了,。 上面是《算法導(dǎo)論》中右旋的示意圖,。 RIGHT-ROTATE(T, y) 01 x ← left[y] // 前提:這里假設(shè)y的左孩子為x,。下面開始正式操作 02 left[y] ← right[x] // 將 “x的右孩子” 設(shè)為 “y的左孩子”,,即 將β設(shè)為y的左孩子 03 p[right[x]] ← y // 將 “y” 設(shè)為 “x的右孩子的父親”,即 將β的父親設(shè)為y 04 p[x] ← p[y] // 將 “y的父親” 設(shè)為 “x的父親” 05 if p[y] = nil[T] 06 then root[T] ← x // 情況1:如果 “y的父親” 是空節(jié)點(diǎn),,則將x設(shè)為根節(jié)點(diǎn) 07 else if y = right[p[y]] 08 then right[p[y]] ← x // 情況2:如果 y是它父節(jié)點(diǎn)的右孩子,,則將x設(shè)為“y的父節(jié)點(diǎn)的左孩子” 09 else left[p[y]] ← x // 情況3:(y是它父節(jié)點(diǎn)的左孩子) 將x設(shè)為“y的父節(jié)點(diǎn)的左孩子” 10 right[x] ← y // 將 “y” 設(shè)為 “x的右孩子” 11 p[y] ← x // 將 “y的父節(jié)點(diǎn)” 設(shè)為 “x” 理解上面的代碼之后,下面以一個(gè)更鮮明的圖對右旋轉(zhuǎn)進(jìn)行說明,。
(01) 左旋 和 右旋 是相對的兩個(gè)概念,,原理類似。理解一個(gè)也就理解了另一個(gè),。 (02) 下面談?wù)勅绾螀^(qū)分 左旋 和 右旋,。
3.3 區(qū)分 左旋 和 右旋無論 左旋 或 右旋,,它們都是以某一個(gè)節(jié)點(diǎn)為中心點(diǎn),。注意:這里,我們理解成以節(jié)點(diǎn)(節(jié)點(diǎn)x)進(jìn)行旋轉(zhuǎn),,而不是以一個(gè)分支(分支xy軸 或 分支xz軸)進(jìn)行旋轉(zhuǎn)!??! 我們以圖來進(jìn)行說明。 左旋示例圖(以x為節(jié)點(diǎn)進(jìn)行左旋): z x / / \ --(左旋)--> x y z / y 對x進(jìn)行左旋,,意味著,,將“x的右孩子”設(shè)為“x的父親節(jié)點(diǎn)”;即,,將 x變成了一個(gè)左節(jié)點(diǎn)(x成了為z的左孩子),!。 因此,,左旋中的“左”,,意味著“被旋轉(zhuǎn)的節(jié)點(diǎn)將變成一個(gè)左節(jié)點(diǎn)”。
y x \ / \ --(右旋)--> x y z z 對x進(jìn)行右旋,,意味著,,將“x的左孩子”設(shè)為“x的父親節(jié)點(diǎn)”;即,,將 x變成了一個(gè)右節(jié)點(diǎn)(x成了為y的右孩子),! 因此,,右旋中的“右”,意味著“被旋轉(zhuǎn)的節(jié)點(diǎn)將變成一個(gè)右節(jié)點(diǎn)”,。
3.4 添加操作向一顆含有n個(gè)節(jié)點(diǎn)的紅黑樹中插入一個(gè)節(jié)點(diǎn),,可以在時(shí)間O(lgn)內(nèi)完成。 將節(jié)點(diǎn)z插入紅黑樹T內(nèi),。需要執(zhí)行的操作依次時(shí):首先,,將T當(dāng)作一顆二叉樹,將z插入,;然后,,將z著色為紅色;最后,,通過RB-INSERT-FIXUP來對節(jié)點(diǎn)重新著色并旋轉(zhuǎn),,以此來保證刪除節(jié)點(diǎn)后的樹仍然是一顆紅黑樹。 (01) 將T當(dāng)作一顆二叉樹,,將z插入,。 (02) 將z著色為紅色。 將插入的節(jié)點(diǎn)著色為紅色,,不會(huì)違背“特性(5)”;而若將插入的節(jié)點(diǎn)著色為黑色,,會(huì)違背該特性,。 (03) 通過RB-INSERT-FIXUP來對節(jié)點(diǎn)重新著色并旋轉(zhuǎn)。 下面是《算法導(dǎo)論》中 “向紅黑樹T中插入節(jié)點(diǎn)z”的偽代碼 RB-INSERT(T, z) 01 y ← nil[T] // 新建節(jié)點(diǎn)“y”,,將y設(shè)為空節(jié)點(diǎn)。 02 x ← root[T] // 設(shè)“紅黑樹T”的根節(jié)點(diǎn)為“x” 03 while x ≠ nil[T] // 找出要插入的節(jié)點(diǎn)“z”在二叉樹T中的位置“y” 04 do y ← x 05 if key[z] < key[x] 06 then x ← left[x] 07 else x ← right[x] 08 p[z] ← y // 設(shè)置 “z的父親” 為 “y” 09 if y = nil[T] 10 then root[T] ← z // 情況1:若y是空節(jié)點(diǎn),,則將z設(shè)為根 11 else if key[z] < key[y] 12 then left[y] ← z // 情況2:若“z所包含的值” < “y所包含的值”,,則將z設(shè)為“y的左孩子” 13 else right[y] ← z // 情況3:(“z所包含的值” >= “y所包含的值”)將z設(shè)為“y的右孩子” 14 left[z] ← nil[T] // z的左孩子設(shè)為空 15 right[z] ← nil[T] // z的右孩子設(shè)為空。至此,,已經(jīng)完成將“節(jié)點(diǎn)z插入到二叉樹”中了,。 16 color[z] ← RED // 將z著色為“紅色” 17 RB-INSERT-FIXUP(T, z) // 通過RB-INSERT-FIXUP對紅黑樹的節(jié)點(diǎn)進(jìn)行顏色修改以及旋轉(zhuǎn),讓樹T仍然是一顆紅黑樹 結(jié)合偽代碼以及為代碼上面的說明,,先理解RB-INSERT,。理解了RB-INSERT之后,我們接著對 RB-INSERT-FIXUP的偽代碼進(jìn)行說明 RB-INSERT-FIXUP(T, z) 01 while color[p[z]] = RED // 若“當(dāng)前節(jié)點(diǎn)(z)的父節(jié)點(diǎn)是紅色”,,則進(jìn)行以下處理,。 02 do if p[z] = left[p[p[z]]] // 若“z的父節(jié)點(diǎn)”是“z的祖父節(jié)點(diǎn)的左孩子”,則進(jìn)行以下處理,。 03 then y ← right[p[p[z]]] // 將y設(shè)置為“z的叔叔節(jié)點(diǎn)(z的祖父節(jié)點(diǎn)的右孩子)” 04 if color[y] = RED // Case 1條件:叔叔是紅色 05 then color[p[z]] ← BLACK ? Case 1 // (01) 將“父節(jié)點(diǎn)”設(shè)為黑色,。 06 color[y] ← BLACK ? Case 1 // (02) 將“叔叔節(jié)點(diǎn)”設(shè)為黑色。 07 color[p[p[z]]] ← RED ? Case 1 // (03) 將“祖父節(jié)點(diǎn)”設(shè)為“紅色”,。 08 z ← p[p[z]] ? Case 1 // (04) 將“祖父節(jié)點(diǎn)”設(shè)為“當(dāng)前節(jié)點(diǎn)”(紅色節(jié)點(diǎn)) 09 else if z = right[p[z]] // Case 2條件:叔叔是黑色,,且當(dāng)前節(jié)點(diǎn)是右孩子 10 then z ← p[z] ? Case 2 // (01) 將“父節(jié)點(diǎn)”作為“新的當(dāng)前節(jié)點(diǎn)”。 11 LEFT-ROTATE(T, z) ? Case 2 // (02) 以“新的當(dāng)前節(jié)點(diǎn)”為支點(diǎn)進(jìn)行左旋,。 12 color[p[z]] ← BLACK ? Case 3 // Case 3條件:叔叔是黑色,,且當(dāng)前節(jié)點(diǎn)是左孩子,。(01) 將“父節(jié)點(diǎn)”設(shè)為“黑色”。 13 color[p[p[z]]] ← RED ? Case 3 // (02) 將“祖父節(jié)點(diǎn)”設(shè)為“紅色”,。 14 RIGHT-ROTATE(T, p[p[z]]) ? Case 3 // (03) 以“祖父節(jié)點(diǎn)”為支點(diǎn)進(jìn)行右旋,。 15 else (same as then clause with "right" and "left" exchanged) // 若“z的父節(jié)點(diǎn)”是“z的祖父節(jié)點(diǎn)的右孩子”,將上面的操作中“right”和“l(fā)eft”交換位置,,然后依次執(zhí)行。 16 color[root[T]] ← BLACK 總的來說:當(dāng)節(jié)點(diǎn)z被著色為紅色節(jié)點(diǎn),并插入二叉樹時(shí),,有三種情況。 情況一:被插入的節(jié)點(diǎn)是根節(jié)點(diǎn),。 情況二:被插入的節(jié)點(diǎn)的父節(jié)點(diǎn)是黑色。 情況三:被插入的節(jié)點(diǎn)的父節(jié)點(diǎn)是紅色。
Case 1:叔叔是紅色Case 1 現(xiàn)象說明:當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)是紅色,,且當(dāng)前節(jié)點(diǎn)的祖父節(jié)點(diǎn)的另一個(gè)子節(jié)點(diǎn)(叔叔節(jié)點(diǎn))也是紅色,。 下面談?wù)劄槭裁匆@樣處理。(建議理解的時(shí)候,,通過下面的圖進(jìn)行對比) Case 1 處理前[當(dāng)前節(jié)點(diǎn)是4]:
Case 1 處理后:
Case 2:叔叔是黑色,且當(dāng)前節(jié)點(diǎn)是右孩子Case 2 現(xiàn)象說明:當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)是紅色,,叔叔節(jié)點(diǎn)是黑色,且當(dāng)前節(jié)點(diǎn)是其父節(jié)點(diǎn)的右孩子 下面談?wù)劄槭裁匆@樣處理。(建議理解的時(shí)候,通過下面的圖進(jìn)行對比) Case 2 處理前[當(dāng)前節(jié)點(diǎn)是7]: Case 2處理后:
Case 3:叔叔是黑色,且當(dāng)前節(jié)點(diǎn)是左孩子Case 3:叔叔是黑色,,且當(dāng)前節(jié)點(diǎn)是左孩子 下面談?wù)劄槭裁匆@樣處理。(建議理解的時(shí)候,,通過下面的圖進(jìn)行對比) Case 3 處理前[當(dāng)前節(jié)點(diǎn)是2]: Case 3 處理后:
3.5 刪除操作將紅黑樹T內(nèi)的節(jié)點(diǎn)z刪除。需要執(zhí)行的操作依次是:首先,,將T當(dāng)作一顆二叉樹,,將節(jié)點(diǎn)刪除;然后,,通過RB-DELETE-FIXUP來對節(jié)點(diǎn)重新著色并旋轉(zhuǎn),,以此來保證刪除節(jié)點(diǎn)后的樹仍然是一顆紅黑樹。 (01) 將T當(dāng)作一顆二叉樹,,將節(jié)點(diǎn)刪除,。 這和"刪除常規(guī)二叉搜索樹中刪除節(jié)點(diǎn)的方法是一樣的"。分3種情況: 這里有兩點(diǎn)需要說明:第一步中復(fù)制時(shí),,僅僅復(fù)制內(nèi)容,,即將“它的后繼節(jié)點(diǎn)的內(nèi)容”復(fù)制給“該節(jié)點(diǎn)的內(nèi)容”。 這相當(dāng)于用“該節(jié)點(diǎn)的后繼節(jié)點(diǎn)”取代“該節(jié)點(diǎn)”,,之后就刪除“該節(jié)點(diǎn)的后繼節(jié)點(diǎn)”即可,,而不需要?jiǎng)h除“該節(jié)點(diǎn)”(因?yàn)椤霸摴?jié)點(diǎn)”已經(jīng)被“它的后繼節(jié)點(diǎn)”所取代)。 (02) 通過RB-DELETE-FIXUP來對節(jié)點(diǎn)重新著色并旋轉(zhuǎn),以此來保證刪除節(jié)點(diǎn)后的樹仍然是一顆紅黑樹,。 因?yàn)?01)中刪除節(jié)點(diǎn)之后,,可能會(huì)違背紅黑樹的特性。所以需要,,通過RB-DELETE-FIXUP來重新校正,,為當(dāng)前樹保持紅黑樹的特性。
RB-DELETE(T, z) 01 if left[z] = nil[T] or right[z] = nil[T] 02 then y ← z // 若“z的左孩子” 或 “z的右孩子”為空,,則將“z”賦值給 “y”,; 03 else y ← TREE-SUCCESSOR(z) // 否則,將“z的后繼節(jié)點(diǎn)”賦值給 “y”,。 04 if left[y] ≠ nil[T] 05 then x ← left[y] // 若“y的左孩子” 不為空,,則將“y的左孩子” 賦值給 “x”; 06 else x ← right[y] // 否則,,“y的右孩子” 賦值給 “x”,。 07 p[x] ← p[y] // 將“y的父節(jié)點(diǎn)” 設(shè)置為 “x的父節(jié)點(diǎn)” 08 if p[y] = nil[T] 09 then root[T] ← x // 情況1:若“y的父節(jié)點(diǎn)” 為空,則設(shè)置“x” 為 “根節(jié)點(diǎn)”,。 10 else if y = left[p[y]] 11 then left[p[y]] ← x // 情況2:若“y是它父節(jié)點(diǎn)的左孩子”,,則設(shè)置“x” 為 “y的父節(jié)點(diǎn)的左孩子” 12 else right[p[y]] ← x // 情況3:若“y是它父節(jié)點(diǎn)的右孩子”,,則設(shè)置“x” 為 “y的父節(jié)點(diǎn)的右孩子” 13 if y ≠ z 14 then key[z] ← key[y] // 若“y的值” 賦值給 “z”。注意:這里只拷貝z的值給y,,而沒有拷貝z的顏色?。?! 15 copy y's satellite data into z 16 if color[y] = BLACK 17 then RB-DELETE-FIXUP(T, x) // 若“y為黑節(jié)點(diǎn)”,,則調(diào)用 18 return y 結(jié)合偽代碼以及為代碼上面的說明,先理解RB-DELETE,。理解了RB-DELETE之后,,接著對 RB-DELETE-FIXUP的偽代碼進(jìn)行說明 RB-DELETE-FIXUP(T, x) 01 while x ≠ root[T] and color[x] = BLACK 02 do if x = left[p[x]] 03 then w ← right[p[x]] // 若 “x”是“它父節(jié)點(diǎn)的左孩子”,則設(shè)置 “w”為“x的叔叔”(即x為它父節(jié)點(diǎn)的右孩子) 04 if color[w] = RED // Case 1: x是“黑+黑”節(jié)點(diǎn),,x的兄弟節(jié)點(diǎn)是紅色,。(此時(shí)x的父節(jié)點(diǎn)和x的兄弟節(jié)點(diǎn)的子節(jié)點(diǎn)都是黑節(jié)點(diǎn))。 05 then color[w] ← BLACK ? Case 1 // (01) 將x的兄弟節(jié)點(diǎn)設(shè)為“黑色”,。 06 color[p[x]] ← RED ? Case 1 // (02) 將x的父節(jié)點(diǎn)設(shè)為“紅色”,。 07 LEFT-ROTATE(T, p[x]) ? Case 1 // (03) 對x的父節(jié)點(diǎn)進(jìn)行左旋。 08 w ← right[p[x]] ? Case 1 // (04) 左旋后,,重新設(shè)置x的兄弟節(jié)點(diǎn),。 09 if color[left[w]] = BLACK and color[right[w]] = BLACK // Case 2: x是“黑+黑”節(jié)點(diǎn),x的兄弟節(jié)點(diǎn)是黑色,,x的兄弟節(jié)點(diǎn)的兩個(gè)孩子都是黑色,。 10 then color[w] ← RED ? Case 2 // (01) 將x的兄弟節(jié)點(diǎn)設(shè)為“紅色”。 11 x ← p[x] ? Case 2 // (02) 設(shè)置“x的父節(jié)點(diǎn)”為“新的x節(jié)點(diǎn)”,。 12 else if color[right[w]] = BLACK // Case 3: x是“黑+黑”節(jié)點(diǎn),,x的兄弟節(jié)點(diǎn)是黑色;x的兄弟節(jié)點(diǎn)的左孩子是紅色,,右孩子是黑色的,。 13 then color[left[w]] ← BLACK ? Case 3 // (01) 將x兄弟節(jié)點(diǎn)的左孩子設(shè)為“黑色”。 14 color[w] ← RED ? Case 3 // (02) 將x兄弟節(jié)點(diǎn)設(shè)為“紅色”,。 15 RIGHT-ROTATE(T, w) ? Case 3 // (03) 對x的兄弟節(jié)點(diǎn)進(jìn)行右旋,。 16 w ← right[p[x]] ? Case 3 // (04) 右旋后,重新設(shè)置x的兄弟節(jié)點(diǎn),。 17 color[w] ← color[p[x]] ? Case 4 // Case 4: x是“黑+黑”節(jié)點(diǎn),,x的兄弟節(jié)點(diǎn)是黑色;x的兄弟節(jié)點(diǎn)的右孩子是紅色的,。(01) 將x父節(jié)點(diǎn)顏色 賦值給 x的兄弟節(jié)點(diǎn),。 18 color[p[x]] ← BLACK ? Case 4 // (02) 將x父節(jié)點(diǎn)設(shè)為“黑色”。 19 color[right[w]] ← BLACK ? Case 4 // (03) 將x兄弟節(jié)點(diǎn)的右子節(jié)設(shè)為“黑色”。 20 LEFT-ROTATE(T, p[x]) ? Case 4 // (04) 對x的父節(jié)點(diǎn)進(jìn)行左旋,。 21 x ← root[T] ? Case 4 // (05) 設(shè)置“x”為“根節(jié)點(diǎn)”,。 22 else (same as then clause with "right" and "left" exchanged) // 若 “x”是“它父節(jié)點(diǎn)的右孩子”,將上面的操作中“right”和“l(fā)eft”交換位置,,然后依次執(zhí)行,。 23 color[x] ← BLACK 在開始說明RB-DELETE-FIXUP之前,我們再次溫習(xí)一下紅黑樹的幾個(gè)特性: 在RB-DELETE中,,若被刪除的節(jié)點(diǎn)y是黑色的,,則會(huì)產(chǎn)生三個(gè)問題。 RB-DELETE-FIXUP需要解決上面的三個(gè)問題,進(jìn)而保持紅黑樹的全部特性,。 現(xiàn)在,我們面臨的問題,,由解決“違反了特性(2),、(4)、(5)三個(gè)特性”轉(zhuǎn)換成了“解決違反特性(1),、(2),、(4)三個(gè)特性”。 將上面的思想,,可以概括為3種情況。 情況一:x是“紅+黑”節(jié)點(diǎn),。 情況二:x是“黑+黑”節(jié)點(diǎn),,且x是根。 情況三:x是“黑+黑”節(jié)點(diǎn),,且x不是根。這又可以劃分了4種情況:Case 1,、Case 2,、Case 3、Case 4,。
Case 1Case 1 現(xiàn)象說明:x是“黑+黑”節(jié)點(diǎn),,x的兄弟節(jié)點(diǎn)是紅色。(此時(shí)x的父節(jié)點(diǎn)和x的兄弟節(jié)點(diǎn)的子節(jié)點(diǎn)都是黑節(jié)點(diǎn)),。 下面談?wù)劄槭裁匆@樣處理,。(建議理解的時(shí)候,,通過下面的圖進(jìn)行對比) Case 1 處理前[當(dāng)前節(jié)點(diǎn)是A]: Case 1 處理后:
Case 2Case 2 現(xiàn)象說明:x是“黑+黑”節(jié)點(diǎn),x的兄弟節(jié)點(diǎn)是黑色,,x的兄弟節(jié)點(diǎn)的兩個(gè)孩子都是黑色,。 下面談?wù)劄槭裁匆@樣處理,。(建議理解的時(shí)候,通過下面的圖進(jìn)行對比) Case 2 處理前[當(dāng)前節(jié)點(diǎn)是A]: Case 2 處理后:
Case 3Case 3 現(xiàn)象說明:x是“黑+黑”節(jié)點(diǎn),x的兄弟節(jié)點(diǎn)是黑色,;x的兄弟節(jié)點(diǎn)的左孩子是紅色,,右孩子是黑色的。 下面談?wù)劄槭裁匆@樣處理,。(建議理解的時(shí)候,通過下面的圖進(jìn)行對比) Case 3 處理前[當(dāng)前節(jié)點(diǎn)是A]: Case 3 處理后:
Case 4Case 4 現(xiàn)象說明:x是“黑+黑”節(jié)點(diǎn),x的兄弟節(jié)點(diǎn)是黑色,;x的兄弟節(jié)點(diǎn)的左孩子是紅色,,右孩子是黑色的。 下面談?wù)劄槭裁匆@樣處理。(建議理解的時(shí)候,,通過下面的圖進(jìn)行對比) 至此,,我們就完成了Case 4的處理。理解Case 4的核心,,是了解如何“去掉當(dāng)前節(jié)點(diǎn)額外的黑色”,。
Case 4 處理后:
OK!至此,,紅黑樹的理論知識差不多講完了,。后續(xù)再更新紅黑樹的實(shí)現(xiàn)代碼! |
|