Java基礎-理解紅黑樹(插入)

吾乃上將軍邢道榮發表於2019-03-03

     周圍有一些朋友總說:“面試時候看到紅黑樹真的頭大!各種情況太難記了。”確實,如果僅僅想通過記憶來搞定紅黑樹那確實有點難度的,但是如果理解的話,紅黑樹其實很簡單,所以我就分享一下我對紅黑樹的理解。

1.簡單複習下紅黑樹的規則。

  1. 節點必須是紅色或者黑色。
  2. 根節點必須是黑色。
  3. 葉節點(NIL)是黑色的。(NIL節點無資料,是空節點)
  4. 不能出現連續兩個紅色節點。
  5. 從任一節點出發到其每個葉子節點的路徑,黑色節點的數量是相等的。

2.先講解一波操作,後面再給出論證

插入操作如下,

  1. 每次插入第一步,將新插入節點設定為紅色。
  2. 每次插入最後一步,將根節點設定為黑色。
  3. 當且僅當新插入節點的父節點為紅色時,重新調整紅黑樹的平衡(調整步驟如下)。
根據插入操作3,只有新插入節點父節點為紅色時,才需要調節紅黑樹,那麼父節點為紅色時會有幾種情況呢?理論上講只有兩種。

第一種:新插入節點 父節點的 兄弟節點 為黑色(左下角節點為新插入節點)

Java基礎-理解紅黑樹(插入)

第二種:新插入節點 父節點的 兄弟節點 為紅色(左下角節點為新插入節點)

Java基礎-理解紅黑樹(插入)

兩種情況逐個分析。

第一種情況下,想要恢復樹的平衡,只需要將連續的兩個紅色節點,分一個給另外一個分支即可。這樣的話,如果原來的樹是平衡的,新樹也必然平衡(兩個分支的黑色節點數量並未變化)。

Java基礎-理解紅黑樹(插入)

當然說是一回事,做是另一回事。下面就看看實際情況下,如何操作。

Java基礎-理解紅黑樹(插入)


原樹已經有12,10 ,13三個元素,新插入了一個8節點,此時,8與其父節點10都為紅色,需要調整。將10設定為黑色,將12設定為紅色,然後對節點12進行左旋操作(其實就是把8,10,12這三個順序節點,重新以中間值10為中心在排一下)。

Java基礎-理解紅黑樹(插入)

如果新插入的節點是11那該怎麼辦呢。

Java基礎-理解紅黑樹(插入)

此時需要重排的三個節點為12,10,11,但是中間值11在最下面,直接重排不方便。所以需要多一步操作,對10節點進行右旋操作。

Java基礎-理解紅黑樹(插入)

這樣12 ,11 ,10 這三個節點也是順序排列了。下一步操作就同上。如果從右邊插入的話,操作也一樣,映象一下就ok。

現在再分析第二種情況(左下角為新插入節點)。

Java基礎-理解紅黑樹(插入)

這種情況處理起來更簡單,只需要將新插入節點的父節點,以及父節點的兄弟節點一起變成黑色,然後將爺爺節點變紅即可(兩個分支的黑色節點數量依然沒有變化)。

Java基礎-理解紅黑樹(插入)

因為從爺爺節點往下,每個分支原來是一個黑色節點,現在依然是一個黑色節點,所以樹還是平衡的,但是需要注意的是,因為爺爺節點由黑變紅了。所以還得以爺爺節點為基準,迭代向上判斷。直到爺爺節點的父節點為黑色或者爺爺節點為根節點為止。至於迭代中可能的情況,也無非就是我們列出來的這兩種,參照一下即可。

3.最後論證插入操作的合理性:

紅黑樹規則:

  1. 節點必須是紅色或者黑色。
  2. 根節點必須是黑色。
  3. 葉節點(NIL)是黑色的。(NIL節點無資料,是空節點)
  4. 不能出現連續兩個紅色節點。
  5. 從任一節點出發到其每個葉子節點的路徑,黑色節點的數量是相等的。
插入操作
  1. 每次插入第一步,將新插入節點設定為紅色。
  2. 每次插入最後一步,將根節點設定為黑色。
  3. 當且僅當新插入節點的父節點為紅色時,重新調整紅黑樹的平衡


首先,每次插入的第一步將插入節點設定為紅色,因為如果樹原本是平衡的話,插入一個紅色節點並不會影響到規則5(從任一節點出發到其每個葉子節點的路徑,黑色節點的數量是相等的)。

其次,在插入最後一步將根節點設定為黑色,這樣規則2(根節點必須是黑色)就永遠滿足。

最後依據插入操作3(當且僅當新插入節點的父節點為紅色時,重新調整紅黑樹的平衡),以及調整步驟,每次調整過後,都可以保證規則4(不能出現連續兩個紅色節點)也是可以滿足的。

這樣一來,只要嚴格遵循插入的這3條操作,就可以嚴格的保證紅黑樹的平衡了。或許你會問剛開始的第一條論證有一個前提條件“樹原本是平衡的話”,如果這個前提條件不滿足怎麼辦?

其實當你插入第一個根節點時,樹已經處於了平衡的狀態。所以只要一開始就遵循插入操作,根本就不會存在樹不平衡的情況。所以這個插入操作是合理的。

下一篇:紅黑樹的刪除操作


相關文章