紅黑樹(shù)

紅黑樹(shù)圖
Java在實(shí)現(xiàn)TreeMap中用到了紅黑樹(shù),在此記錄自己的理解。

定義

紅黑樹(shù)是二叉搜索樹(shù)的一種實(shí)現(xiàn)方式,任意一條到葉結(jié)點(diǎn)的路徑不會(huì)比其他路徑長(zhǎng)出2倍。

性質(zhì)

紅黑樹(shù)一共有5點(diǎn)性質(zhì):

  1. 每個(gè)結(jié)點(diǎn)是紅色或者黑色的
  2. 根結(jié)點(diǎn)是黑色的
  3. 葉結(jié)點(diǎn)是黑色的
  4. 如果一個(gè)結(jié)點(diǎn)是紅色的,那么它的兒子結(jié)點(diǎn)都是黑色的
  5. 每一個(gè)結(jié)點(diǎn)到其葉結(jié)點(diǎn)的所有路徑中,黑色結(jié)點(diǎn)的個(gè)數(shù)相同

紅黑樹(shù)的一個(gè)結(jié)點(diǎn)如果沒(méi)有兒子,那么它將指向一個(gè)NIL結(jié)點(diǎn),該NIL結(jié)點(diǎn)為葉結(jié)點(diǎn)。同理,根結(jié)點(diǎn)的父親也指向NIL結(jié)點(diǎn)。NIL結(jié)點(diǎn)為黑色的,其left、right、p、key可以為任何值。

為了便于在紅黑樹(shù)執(zhí)行增加或刪除操作時(shí)的邊界處理,使用一個(gè)哨兵結(jié)點(diǎn)T.nil代表NIL。

操作

一個(gè)二叉樹(shù)的基本操作有增加、刪除和查詢(xún)。紅黑樹(shù)的基本操作時(shí)間復(fù)雜度為O(lgn)。為了保證紅黑樹(shù)進(jìn)行增加或刪除操作后仍然保持其性質(zhì),需要在基本操作之后進(jìn)行處理,使其滿(mǎn)足特性。

旋轉(zhuǎn)

旋轉(zhuǎn)是修改紅黑樹(shù)結(jié)構(gòu)的一種方法。


紅黑樹(shù)_旋轉(zhuǎn).jpg
增加

往紅黑樹(shù)中增加一個(gè)結(jié)點(diǎn)z,z結(jié)點(diǎn)被設(shè)為紅色,并且占據(jù)了原某一葉子結(jié)點(diǎn)的位置。由于在加入z結(jié)點(diǎn)之前紅黑樹(shù)滿(mǎn)足性質(zhì),在加入z結(jié)點(diǎn)后,樹(shù)可能不滿(mǎn)足的性質(zhì)為性質(zhì)4,即出現(xiàn)某一紅色結(jié)點(diǎn)的兒子仍為紅色結(jié)點(diǎn)。此時(shí)需要處理該紅色z結(jié)點(diǎn),主要方法為在滿(mǎn)足其余性質(zhì)的情況下,不斷將紅色上移(不是移動(dòng)結(jié)點(diǎn),而是不斷更改相鄰結(jié)點(diǎn)的顏色),直到根結(jié)點(diǎn)為紅色,將根結(jié)點(diǎn)變?yōu)楹谏蛘咴谀骋徊缴弦浦?,紅色移動(dòng)到了滿(mǎn)足所有性質(zhì)的位置。

當(dāng)z結(jié)點(diǎn)的父親結(jié)點(diǎn)為黑色時(shí),不存在不滿(mǎn)足的性質(zhì),以下討論z結(jié)點(diǎn)的父親為紅色時(shí)的情況。我們不妨另z為其父結(jié)點(diǎn)的左兒子,對(duì)于z為其父結(jié)點(diǎn)右兒子的情況,可以通過(guò)旋轉(zhuǎn)將其變?yōu)樽髢鹤印?/p>

增加_右兒子變左兒子.jpg

假設(shè)z.p=z.p.p.left,另一種情況與此相似。此時(shí)只需要按照z.p.p.right,即z的叔結(jié)點(diǎn)的顏色進(jìn)行分類(lèi)討論即可。

  1. 叔結(jié)點(diǎn)為紅色


    叔結(jié)點(diǎn)為紅色.png

將z.p和z.p.p.right變?yōu)楹谏?,將z.p.p變?yōu)榧t色。經(jīng)過(guò)上述操作后,原z結(jié)點(diǎn)滿(mǎn)足性質(zhì)4,另z'=z.p.p,繼續(xù)以處理z的方式處理z'。

  1. 叔結(jié)點(diǎn)為黑色


    增加_叔結(jié)點(diǎn)是黑色.png

將z.p.p設(shè)為紅色,將z.p設(shè)為黑色,將z.p.p進(jìn)行左旋轉(zhuǎn)。這里對(duì)p結(jié)點(diǎn)進(jìn)行右旋轉(zhuǎn)后,由于q結(jié)點(diǎn)不再是z的父輩結(jié)點(diǎn),導(dǎo)致z路徑上的黑色結(jié)點(diǎn)減少一個(gè),將p變?yōu)楹谏鬂M(mǎn)足,此時(shí)滿(mǎn)足性質(zhì)4,完成處理。

刪除

紅黑樹(shù)的刪除基于TRANSPLANT操作,以下為其實(shí)現(xiàn)。

RB-TRANSPLANT(T,u,v)
    if(u.p==T.nil)
        T.root=v
    else if u==u.p.left
        u.p.left=v
    else 
        u.p.right=v
    v.p=u.p       

在紅黑樹(shù)上刪除一個(gè)結(jié)點(diǎn)z后,我們用其子樹(shù)上的y結(jié)點(diǎn)連接z的父結(jié)點(diǎn),并將y結(jié)點(diǎn)的顏色設(shè)為與z結(jié)點(diǎn)相同,這里需要分類(lèi)討論z的兒子結(jié)點(diǎn)個(gè)數(shù)。

  1. 當(dāng)左兒子為NIL時(shí),y結(jié)點(diǎn)為z的右兒子。


    刪除_左左兒子為nil.png
  2. 當(dāng)右兒子為NIL時(shí),y結(jié)點(diǎn)為z的左兒子。


    刪除_右兒子為nil.png
  3. 當(dāng)左、右兒子均不為NIL時(shí),y結(jié)點(diǎn)為樹(shù)中比z結(jié)點(diǎn)大的最小結(jié)點(diǎn),即z結(jié)點(diǎn)右子樹(shù)中的最小結(jié)點(diǎn)。


    刪除_左右兒子非nil.png

在第1或第2的情況下下,如果z結(jié)點(diǎn)為黑色,將y放置到z的位置后,y父輩到葉結(jié)點(diǎn)的路徑上的黑色結(jié)點(diǎn)個(gè)數(shù)減一;或者情況3下y結(jié)點(diǎn)為黑色,將y放置到z的位置后,y的右兒子的父輩到葉結(jié)點(diǎn)的路徑到上的黑色結(jié)點(diǎn)個(gè)數(shù)減一。為了保證紅黑樹(shù)的性質(zhì)5,我們暫時(shí)增加該結(jié)點(diǎn)(情況1、2為y結(jié)點(diǎn),情況3為x結(jié)點(diǎn))的“黑色的程度”,即計(jì)算路徑上的黑色結(jié)點(diǎn)時(shí)多計(jì)算一次該結(jié)點(diǎn)的黑色次數(shù)。

我們處理該多余黑色次數(shù)的主要辦法與之前的方法相似,不斷將該黑色次數(shù)上移,直到遇到一個(gè)紅色結(jié)點(diǎn),將其變?yōu)楹谏驅(qū)⒑谏螖?shù)上移到根節(jié)點(diǎn)再清除。

統(tǒng)一另增加了黑色程度的結(jié)點(diǎn)為x,不妨令x=x.p.left,對(duì)于x=x.p.right的情況與之相似。

  1. x結(jié)點(diǎn)為紅色
    只需要將x結(jié)點(diǎn)變?yōu)楹谏?,即可使?shù)滿(mǎn)足性質(zhì)5。
  2. x結(jié)點(diǎn)為黑色,x兄弟結(jié)點(diǎn)w為紅色(此時(shí)x的父結(jié)點(diǎn)為黑色)
    將x.p設(shè)為紅色,將x兄弟結(jié)點(diǎn)w設(shè)為黑色,并對(duì)x.p進(jìn)行左旋轉(zhuǎn),即可通過(guò)下面的分類(lèi)進(jìn)行處理。


    刪除_case2.png
  3. x結(jié)點(diǎn)為黑色,x兄弟結(jié)點(diǎn)w為黑色,且w的兒子均為黑色
    將x多余的黑色次數(shù)上移給x.p,并將w結(jié)點(diǎn)設(shè)為紅色。令x'=x.p,繼續(xù)循環(huán)。


    刪除_case3.png
  4. x結(jié)點(diǎn)為黑色,x兄弟結(jié)點(diǎn)w為黑色,且w左兒子為紅色,w右兒子為黑色
    將w設(shè)為紅色,w左兒子設(shè)為黑色,對(duì)w進(jìn)行右旋轉(zhuǎn),使用下面的分類(lèi)進(jìn)行處理。


    刪除_case4.png
  5. x結(jié)點(diǎn)為黑色,x兄弟結(jié)點(diǎn)w為黑色,且w右兒子為紅色
  • 若x.p為黑色,x.p左旋轉(zhuǎn),消除黑色次數(shù)


    刪除_case5_1.png
  • 若x.p為紅色,x.p設(shè)為黑色,w設(shè)為紅色,x.p左旋轉(zhuǎn),消除黑色次數(shù)


    刪除_case5_2.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 0.目錄 1.算法導(dǎo)論的紅黑樹(shù)本質(zhì)上是2-3-4樹(shù) 2.紅黑樹(shù)的結(jié)構(gòu)和性質(zhì) 3.紅黑樹(shù)的插入 4.紅黑樹(shù)的刪除 5...
    王偵閱讀 2,749評(píng)論 1 2
  • 這個(gè)周看算法導(dǎo)論,看到紅黑樹(shù),看的我云里霧里繞啊。雖然最后看懂了,據(jù)我估計(jì),要是過(guò)一個(gè)星期不看保證忘干凈,因此決定...
    充滿(mǎn)活力的早晨閱讀 2,072評(píng)論 0 3
  • 寫(xiě)在前面 當(dāng)在10億數(shù)據(jù)進(jìn)行不到30次比較就能查找到目標(biāo)時(shí),不禁感嘆編程之魅力!人類(lèi)之偉大呀! —— 學(xué)紅黑樹(shù)有感...
    安卓大叔閱讀 662,971評(píng)論 262 1,258
  • 什么是紅黑樹(shù)? 紅黑樹(shù)是一棵二叉搜索樹(shù),它的結(jié)點(diǎn)上新增了一個(gè)存儲(chǔ)位來(lái)表示結(jié)點(diǎn)的顏色,顏色可以是紅或者黑。通過(guò)顏色進(jìn)...
    MccreeFei閱讀 646評(píng)論 0 0
  • 原文鏈接 二叉查找樹(shù) 由于紅黑樹(shù)本質(zhì)上就是一棵二叉查找樹(shù),所以在了解紅黑樹(shù)之前,咱們先來(lái)看下二叉查找樹(shù)。 二叉查找...
    非典型程序員閱讀 2,935評(píng)論 2 5

友情鏈接更多精彩內(nèi)容