日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

教你透徹了解紅黑樹

 武神將 2011-01-03
------------------
本文參考:Google、算法導(dǎo)論、STL源碼剖析、計(jì)算機(jī)程序設(shè)計(jì)藝術(shù)。
本人聲明:個(gè)人原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處。

更多請(qǐng)參考:
http://blog.csdn.net/v_JULY_v/archive/2010/12/29/6105630.aspx
詳情,參見My BLog:
http://blog.csdn.net/v_JULY_v

一、紅黑樹的介紹
先來看下算法導(dǎo)論對(duì)R-B Tree的介紹:
紅黑樹,一種二叉查找樹,但在每個(gè)結(jié)點(diǎn)上增加一個(gè)存儲(chǔ)位表示結(jié)點(diǎn)的顏色,可以是Red或Black。
通過對(duì)任何一條從根到葉子的路徑上各個(gè)結(jié)點(diǎn)著色方式的限制,紅黑樹確保沒有一條路徑會(huì)比其他路徑長(zhǎng)出倆倍,因而是接近平衡的。  

前面說了,紅黑樹,是一種二叉查找樹,既然是二叉查找樹,那么它必滿足二叉查找樹的一般性質(zhì)。
下面,再具體介紹紅黑樹之前,咱們先來了解下 二叉查找樹的一般性質(zhì):
1.在一棵二叉查找樹上,執(zhí)行查找、插入、刪除等操作,的時(shí)間復(fù)雜度為O(lgn)。
因?yàn)椋豢糜蒼個(gè)結(jié)點(diǎn),隨機(jī)構(gòu)造的二叉查找樹的高度為O(lgn),所以順理成章,一般操作的執(zhí)行時(shí)間為O(lgn)。
(至于n個(gè)結(jié)點(diǎn)的二叉樹高度為O(lgn)的證明,可參考算法導(dǎo)論 第12章 二叉查找樹。)
2.但若是一棵具有n個(gè)結(jié)點(diǎn)的線性鏈,則此些操作最壞情況運(yùn)行時(shí)間為O(n)。

而紅黑樹,能保證在最壞情況下,基本的動(dòng)態(tài)幾何操作的時(shí)間均為O(lgn)。
ok,我們知道,紅黑樹上每個(gè)結(jié)點(diǎn)內(nèi)含五個(gè)域,color,key,left,right。如果相應(yīng)的指針域沒有,則設(shè)為NIL。

一般的,紅黑樹,滿足一下性質(zhì),即只有滿足一下性質(zhì)的樹,我們才稱之為紅黑樹:
1)每個(gè)結(jié)點(diǎn)要么是紅的,要么是黑的。
2)根結(jié)點(diǎn)是黑的。
3)每個(gè)葉結(jié)點(diǎn),即空結(jié)點(diǎn)(NIL)是黑的。
4)如果一個(gè)結(jié)點(diǎn)是紅的,那么它的倆個(gè)兒子都是黑的。
5)對(duì)每個(gè)結(jié)點(diǎn),從該結(jié)點(diǎn)到其子孫結(jié)點(diǎn)的所有路徑上包含相同數(shù)目的黑結(jié)點(diǎn)。

下圖所示,即是一顆紅黑樹:

此圖忽略了葉子和根部的父結(jié)點(diǎn)??傊?,可以這樣表示,就對(duì)了。:D。

二、樹的旋轉(zhuǎn)知識(shí)
當(dāng)我們?cè)趯?duì)紅黑樹進(jìn)行插入和刪除等操作時(shí),對(duì)樹做了修改,那么可能會(huì)違背紅黑樹的性質(zhì)。
為了保持紅黑樹的性質(zhì),我們可以通過對(duì)樹進(jìn)行旋轉(zhuǎn),即修改樹種某些結(jié)點(diǎn)的顏色及指針結(jié)構(gòu),以達(dá)到對(duì)紅黑樹進(jìn)行
插入、刪除結(jié)點(diǎn)等操作時(shí),紅黑樹依然能保持它特有的性質(zhì)(如上文所述的,五點(diǎn)性質(zhì))。

樹的旋轉(zhuǎn),分為左旋和右旋,以下借助圖來做形象的解釋和介紹:
1.左旋


如上圖所示:
當(dāng)在某個(gè)結(jié)點(diǎn)pivot上,做左旋操作時(shí),我們假設(shè)它的右孩子y不是NIL[T],pivot可以為樹內(nèi)任意右孩子而不是NIL[T]的結(jié)點(diǎn)。
左旋以pivot到y(tǒng)之間的鏈為“支軸”進(jìn)行,它使y成為該孩子樹新的根,而y的左孩子b則成為pivot的右孩子。
 
來看算法導(dǎo)論對(duì)此操作的算法實(shí)現(xiàn)(以x代替上述的pivot):
C/C++ code
LEFT-ROTATE(T, x) 1 y ← right[x] ? Set y. 2 right[x] ← left[y] ? Turn y's left subtree into x's right subtree. 3 p[left[y]] ← x 4 p[y] ← p[x] ? Link x's parent to y. 5 if p[x] = nil[T] 6 then root[T] ← y 7 else if x = left[p[x]] 8 then left[p[x]] ← y 9 else right[p[x]] ← y 10 left[y] ← x ? Put x on y's left. 11 p[x] ← y

 

2.右旋
右旋與左旋差不多,再此不做詳細(xì)介紹。


對(duì)于樹的旋轉(zhuǎn),能保持不變的只有原樹的搜索性質(zhì),而原樹的紅黑性質(zhì)則不能保持,
在紅黑樹的數(shù)據(jù)插入和刪除后可利用旋轉(zhuǎn)和顏色重涂來恢復(fù)樹的紅黑性質(zhì)。

至于有些書如 STL源碼剖析有對(duì)雙旋的描述,其實(shí)雙旋只是單旋的兩次應(yīng)用,并無新的內(nèi)容,
因此這里就不再介紹了,而且左右旋也是相互對(duì)稱的,只要理解其中一種旋轉(zhuǎn)就可以了。


三、紅黑樹插入、刪除操作的具體實(shí)現(xiàn)
ok,接下來,咱們來具體了解紅黑樹的插入操作。
向一棵含有n個(gè)結(jié)點(diǎn)的紅黑樹插入一個(gè)新結(jié)點(diǎn)的操作可以在O(lgn)時(shí)間內(nèi)完成。

算法導(dǎo)論:
C/C++ code
RB-INSERT(T, z) 1 y ← nil[T] 2 x ← root[T] 3 while x ≠ nil[T] 4 do y ← x 5 if key[z] < key[x] 6 then x ← left[x] 7 else x ← right[x] 8 p[z] ← y 9 if y = nil[T] 10 then root[T] ← z 11 else if key[z] < key[y] 12 then left[y] ← z 13 else right[y] ← z 14 left[z] ← nil[T] 15 right[z] ← nil[T] 16 color[z] ← RED 17 RB-INSERT-FIXUP(T, z)

咱們來具體分析下,此段代碼:
RB-INSERT(T, z),將z插入紅黑樹T 之內(nèi)。

為保證紅黑性質(zhì)在插入操作后依然保持,上述代碼調(diào)用了一個(gè)輔助程序RB-INSERT-FIXUP
來對(duì)結(jié)點(diǎn)進(jìn)行重新著色,并旋轉(zhuǎn)。

14 left[z] ← nil[T]
15 right[z] ← nil[T] //保持正確的樹結(jié)構(gòu)
第16行,將z著為紅色,由于將z著為紅色可能會(huì)違背某一條紅黑樹的性質(zhì),
所以,在第17行,調(diào)用RB-INSERT-FIXUP(T,z)來保持紅黑樹的性質(zhì)。

RB-INSERT-FIXUP(T, z),如下所示:
C/C++ code
1 while color[p[z]] = RED 2 do if p[z] = left[p[p[z]]] 3 then y ← right[p[p[z]]] 4 if color[y] = RED 5 then color[p[z]] ← BLACK ? Case 1 6 color[y] ← BLACK ? Case 1 7 color[p[p[z]]] ← RED ? Case 1 8 z ← p[p[z]] ? Case 1 9 else if z = right[p[z]] 10 then z ← p[z] ? Case 2 11 LEFT-ROTATE(T, z) ? Case 2 12 color[p[z]] ← BLACK ? Case 3 13 color[p[p[z]]] ← RED ? Case 3 14 RIGHT-ROTATE(T, p[p[z]]) ? Case 3 15 else (same as then clause with "right" and "left" exchanged) 16 color[root[T]] ← BLACK

 
ok,參考一網(wǎng)友的言論,用自己的語言,再來具體解剖下上述倆段代碼。
為了保證闡述清晰,我再寫下紅黑樹的5個(gè)性質(zhì):

1)每個(gè)結(jié)點(diǎn)要么是紅的,要么是黑的。
2)根結(jié)點(diǎn)是黑的。
3)每個(gè)葉結(jié)點(diǎn),即空結(jié)點(diǎn)(NIL)是黑的。
4)如果一個(gè)結(jié)點(diǎn)是紅的,那么它的倆個(gè)兒子都是黑的。
5)對(duì)每個(gè)結(jié)點(diǎn),從該結(jié)點(diǎn)到其子孫結(jié)點(diǎn)的所有路徑上包含相同數(shù)目的黑結(jié)點(diǎn)。

在對(duì)紅黑樹進(jìn)行插入操作時(shí),我們一般總是插入紅色的結(jié)點(diǎn),因?yàn)檫@樣可以在插入過程中盡量避免對(duì)樹的調(diào)整。
那么,我們插入一個(gè)結(jié)點(diǎn)后,可能會(huì)使原樹的哪些性質(zhì)改變列?
由于,我們是按照二叉樹的方式進(jìn)行插入,因此元素的搜索性質(zhì)不會(huì)改變。

如果插入的結(jié)點(diǎn)是根結(jié)點(diǎn),性質(zhì)2會(huì)被破壞,如果插入結(jié)點(diǎn)的父結(jié)點(diǎn)是紅色,則會(huì)破壞性質(zhì)4。
因此,總而言之,插入一個(gè)紅色結(jié)點(diǎn)只會(huì)破壞性質(zhì)2或性質(zhì)4。
我們的回復(fù)策略很簡(jiǎn)單,
其一、把出現(xiàn)違背紅黑樹性質(zhì)的結(jié)點(diǎn)向上移,如果能移到根結(jié)點(diǎn),那么很容易就能通過直接修改根結(jié)點(diǎn)來恢復(fù)紅黑樹的性質(zhì)。直接通過修改根結(jié)點(diǎn)來恢復(fù)紅黑樹應(yīng)滿足的性質(zhì)。
其二、窮舉所有的可能性,之后把能歸于同一類方法處理的歸為同一類,不能直接處理的化歸到下面的幾種情況,

情況1:插入的是根結(jié)點(diǎn)。
原樹是空樹,此情況只會(huì)違反性質(zhì)2。
  對(duì)策:直接把此結(jié)點(diǎn)涂為黑色。
情況2:插入的結(jié)點(diǎn)的父結(jié)點(diǎn)是黑色。
此不會(huì)違反性質(zhì)2和性質(zhì)4,紅黑樹沒有被破壞。
  對(duì)策:什么也不做。
情況3:當(dāng)前結(jié)點(diǎn)的父結(jié)點(diǎn)是紅色且祖父結(jié)點(diǎn)的另一個(gè)子結(jié)點(diǎn)(叔叔結(jié)點(diǎn))是紅色。
此時(shí)父結(jié)點(diǎn)的父結(jié)點(diǎn)一定存在,否則插入前就已不是紅黑樹。
與此同時(shí),又分為父結(jié)點(diǎn)是祖父結(jié)點(diǎn)的左子還是右子,對(duì)于對(duì)稱性,我們只要解開一個(gè)方向就可以了。

在此,我們只考慮父結(jié)點(diǎn)為祖父左子的情況。
同時(shí),還可以分為當(dāng)前結(jié)點(diǎn)是其父結(jié)點(diǎn)的左子還是右子,但是處理方式是一樣的。我們將此歸為同一類。
  對(duì)策:將當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)和叔叔節(jié)點(diǎn)涂黑,祖父結(jié)點(diǎn)涂紅,把當(dāng)前結(jié)點(diǎn)指向祖父節(jié)點(diǎn),從新的當(dāng)前節(jié)點(diǎn)重新開始算法。

針對(duì)情況3,變化前(圖片來源:saturnman):
  變化前:


變化后:


情況4:當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)是紅色,叔叔節(jié)點(diǎn)是黑色,當(dāng)前節(jié)點(diǎn)是其父節(jié)點(diǎn)的右子
對(duì)策:當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)做為新的當(dāng)前節(jié)點(diǎn),以新當(dāng)前節(jié)點(diǎn)為支點(diǎn)左旋。
如下圖所示,變化前:


 變化后:


情況5:當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)是紅色,叔叔節(jié)點(diǎn)是黑色,當(dāng)前節(jié)點(diǎn)是其父節(jié)點(diǎn)的左子
解法:父節(jié)點(diǎn)變?yōu)楹谏?,祖父?jié)點(diǎn)變?yōu)榧t色,在祖父節(jié)點(diǎn)為支點(diǎn)右旋

如下圖所示


變化后:



--------------------------------
 ok,接下來,咱們最后來簡(jiǎn)單了解,紅黑樹的刪除操作:
算法導(dǎo)論一書,給的算法實(shí)現(xiàn): 
RB-DELETE(T, z)
 
C/C++ code
1 if left[z] = nil[T] or right[z] = nil[T] 2 then y ← z 3 else y ← TREE-SUCCESSOR(z) 4 if left[y] ≠ nil[T] 5 then x ← left[y] 6 else x ← right[y] 7 p[x] ← p[y] 8 if p[y] = nil[T] 9 then root[T] ← x 10 else if y = left[p[y]] 11 then left[p[y]] ← x 12 else right[p[y]] ← x 13 if y 3≠ z 14 then key[z] ← key[y] 15 copy y's satellite data into z 16 if color[y] = BLACK 17 then RB-DELETE-FIXUP(T, x) 18 return y


C/C++ code
RB-DELETE-FIXUP(T, x) 1 while x ≠ root[T] and color[x] = BLACK 2 do if x = left[p[x]] 3 then w ← right[p[x]] 4 if color[w] = RED 5 then color[w] ← BLACK ? Case 1 6 color[p[x]] ← RED ? Case 1 7 LEFT-ROTATE(T, p[x]) ? Case 1 8 w ← right[p[x]] ? Case 1 9 if color[left[w]] = BLACK and color[right[w]] = BLACK 10 then color[w] ← RED ? Case 2 11 x p[x] ? Case 2 12 else if color[right[w]] = BLACK 13 then color[left[w]] ← BLACK ? Case 3 14 color[w] ← RED ? Case 3 15 RIGHT-ROTATE(T, w) ? Case 3 16 w ← right[p[x]] ? Case 3 17 color[w] ← color[p[x]] ? Case 4 18 color[p[x]] ← BLACK ? Case 4 19 color[right[w]] ← BLACK ? Case 4 20 LEFT-ROTATE(T, p[x]) ? Case 4 21 x ← root[T] ? Case 4 22 else (same as then clause with "right" and "left" exchanged) 23 color[x] ← BLACK

saturnman:
我們紅黑樹刪除的幾種情況:
(注:以下各種情況,不與上述算法導(dǎo)論之上的代碼相對(duì)應(yīng)。)
情況1:當(dāng)前節(jié)點(diǎn)是紅+黑色
  解法,直接把當(dāng)前節(jié)點(diǎn)染成黑色,結(jié)束。
此時(shí)紅黑樹性質(zhì)全部恢復(fù)。

情況2:當(dāng)前節(jié)點(diǎn)是黑+黑且是根節(jié)點(diǎn)
  解法:什么都不做,結(jié)束

情況3:當(dāng)前節(jié)點(diǎn)是黑+黑且兄弟節(jié)點(diǎn)為紅色(此時(shí)父節(jié)點(diǎn)和兄弟節(jié)點(diǎn)的子節(jié)點(diǎn)分為黑)。
  解法:把父節(jié)點(diǎn)染成紅色,把兄弟結(jié)點(diǎn)染成黑色,之后重新進(jìn)入算法(我們只討論當(dāng)前節(jié)點(diǎn)是其父節(jié)點(diǎn)左孩子時(shí)的情況)。此變換后原紅黑樹性質(zhì)5不變,而把問題轉(zhuǎn)化為兄弟節(jié)點(diǎn)為黑色的情況。
  3.變化前:
..........

===========
更多請(qǐng)參考:
http://blog.csdn.net/v_JULY_v/archive/2010/12/29/6105630.aspx
詳情,參見My BLog:
http://blog.csdn.net/v_JULY_v

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多