1. 程式人生 > >徹底搞懂紅黑樹

徹底搞懂紅黑樹

這裡寫圖片描述

紅黑樹性質

1、每個結點或是紅色的,或是黑色的
2、根節點是黑色的
3、每個葉結點(NIL)是黑色的
4、如果一個節點是紅色的,則它的兩個兒子都是黑色的。
5、對於每個結點,從該結點到其葉子結點構成的所有路徑上的黑結點個數相同。

和AVL樹的比較

AVL樹是一棵嚴格的平衡樹,它所有的子樹都滿足二叉平衡樹的定義。因此AVL樹高被嚴格控制在XXX,因此AVL樹的查詢比較高效。但AVL樹插入、刪除結點後旋轉的次數比紅黑樹多。

紅黑樹用非嚴格的平衡來降低插入刪除時旋轉的次數。

因此,如果你的業務中查詢遠遠多於插入、刪除,那選AVL樹;
如果查詢、插入、刪除頻率差不多,那麼選擇紅黑樹。

插入過程

預設插入的結點為紅色。為何?
因為紅黑樹中黑節點至少是紅節點的兩倍,因此插入節點的父節點為黑色的概率較大,而此時並不需要作任何調整,因此效率較高。

1. 父為黑

title
插入後無需任何操作。由於黑節點個數至少為紅節點的兩倍,因此父為黑的情況較多,而這種情況在插入後無需任何調整,這就是紅黑樹比AVL樹插入效率高的原因!

2. 父為紅

父為紅的情況破壞了紅黑樹的性質,此時需要根據叔叔的顏色來做不同的處理。
title

  1. 叔叔為紅
    title
    此時很簡單,只需交換爸爸、叔叔和爺爺的顏色即可。
    此時若爺爺節點和太爺爺節點顏色相同,再以爺爺節點為起始節點,進行剛才相同的操作,即:根據爺爺的兄弟顏色做相應的操作。

  2. 叔叔為黑
    此時較為複雜,分如下四種情況:
    a)爸爸在左、叔叔在右、我在左
    title
    以爸爸為根節點,進行一次R旋轉。
    b)爸爸在左、叔叔在右、我在右
    title
    title
    先以我為根節點,進行一次L旋轉;
    再以我為根節點,進行一次R旋轉。
    c)叔叔在左、爸爸在右、我在左
    title
    先以我為根節點,進行一次R旋轉;
    再以我為根節點,進行一次L旋轉。
    d)叔叔在左、爸爸在右、我在右
    title
    以爸爸為根節點,進行一次L旋轉。

刪除過程

二叉搜尋樹的刪除

若刪除二叉搜尋樹的節點A,實際上刪除的是二叉搜尋樹中序遍歷的前驅節點,注意:
1. 這個被刪除節點要麼就是一個葉子節點,
2. 要麼有且僅有一個左孩子
然後將孩子頂替它原來的位置,最後將被刪的節點值覆蓋待刪除的那個節點A。

紅黑樹按照二叉搜尋樹的方式刪除節點,之後再進行相應的旋轉操作,使得刪除後的樹仍然是一棵紅黑樹。

定義

  1. 待刪除節點:要刪除的那個節點
  2. 實際刪除節點:待刪除節點的中序遍歷前驅

紅黑樹實際刪除節點的性質

  1. 實際刪除節點要麼是葉子節點,要麼有且僅有一個左孩子;
  2. 若為葉子節點,必為紅色;
  3. 若實際刪除節點還有孩子,則該必為左孩子;
    a)若左孩子為紅色,則實際刪除節點必為黑色;
    b)若左孩子為黑色,則實際刪除節點紅黑均可以。

約定

  1. 藍色箭頭:表示判定點
  2. 在刪除操作開始前,藍色箭頭首先指向實際刪除節點。
  3. 『實際刪除節點』在圖中以『父』表示。

旋轉過程開始:

1. 父為紅色(待刪節點為葉子)

直接刪除父節點即可:
title

2. 父為黑 子為紅(待刪節點為黑、待刪節點子節點為紅+左孩子)

用子節點覆蓋父節點,並保持父節點的顏色:
title

3. 父為黑 子為黑(待刪節點和子節點均為黑)

3.1. 叔叔為紅

PS:叔叔為紅,則爺爺必為黑!

  1. 父在左 叔在右
    a)子節點覆蓋父節點
    b)進行一次左旋
    title

  2. 父在右 叔在左
    a)子節點覆蓋父節點
    b)進行一次右旋

3.2. 叔叔為黑

PS:叔叔、爸爸都為黑,那爺爺顏色就不確定了!

  1. 祖父紅 兩個侄子黑
    以下兩種情況操作一致:
    1.子覆蓋父(刪除)
    2.交換祖父和叔叔的顏色。

    a)父在左 叔在右
    title
    b)父在右 叔在左
    同上。

  2. 祖父黑 兩個侄子黑
    以下兩種情況操作一致:
    1. 祖父染成子節點的顏色;
    2. 子節點染成黑色;
    3. 叔叔染成紅色
    a)父在左 叔在右
    title
    b)父在右 叔在左

  3. 祖父顏色隨意 至少有一個紅侄
    a)紅侄為左左(叔左、紅侄左)
    1. 紅侄進行一次右旋
    2. 紅侄染成黑色
    3. 交換叔叔和祖父的顏色
    title
    b)紅侄為左右(叔左、紅侄右)
    1. 紅侄進行一次右旋+左旋
    2. 紅侄染成父節點顏色;
    3. 父節點染成黑色
    title
    c)紅侄為右左(叔右、紅侄左)
    1. 紅侄進行一次右旋+左旋
    2. 紅侄染成父節點顏色;
    3. 父節點染成黑色;
    title
    d)紅侄為右右(叔右、紅侄右)
    1. 紅侄進行一次左旋
    2. 叔叔染成父節點顏色;
    3. 紅侄染成黑色;
    title

這裡寫圖片描述