紅黑樹的原理以及實現

DeusJin發表於2021-04-06

紅黑樹

紅黑樹基於二叉查詢樹的附加特性

  1. 節點是紅色或黑色。
  2. 根節點是黑色。
  3. 每個葉子節點都是黑色的空節點(葉子結點指為空的葉子結點)。
  4. 每個紅色節點的兩個子節點都是黑色的(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)。
  5. 從任意節點到其每個葉子的所有路徑都包含相同數目的黑色節點。

1. 資料結構

class TreeNode{
    private Boolean color;
    private int val;
    private TreeNode left;
    private TreeNode right;
    private TreeNode parent;
    get,set...
}
class RBTree{
    public boolean add(int val){...}
    public boolean delete(int val){...}
    public void display(){...}
}

2. 左旋以及右旋

2.1 左旋

2.2 右旋

3. 插入

  • 新插入的節點(newNode)為紅色。

  • 按照二分查詢樹插入規則插入。

  • 分情況討論以下情況基本都是為了保持上文所講的的紅黑樹特性4和特5

    1、若newNode為根節點,則變為黑色,插入完畢,返回 true。

    2、若newNode父節點為黑色,則插入完畢,返回 true。

    3、如下圖所示,若newNode父節點為紅色,且叔叔節點存在且為紅色,則父節點與叔叔節點變為黑色,祖父節點變為紅色,newNode = 祖父節點。

    4、如下圖所示,若newNode父節點為紅色,叔叔節點不存在或為黑色,且newNode為父節點右孩子,父節點為祖父節點左孩子,則以父節點為軸左旋,進入情況6.

5、如下圖所示,若newNode父節點為紅色,叔叔節點不存在或為黑色,且newNode為父節點左孩子,父節點為祖父節點右孩子,則以父節點為軸右旋,進入情況7

6、如下圖,此時以祖父節點為軸進行右旋,將祖父節點變為紅色,newNode變為黑色。

7、如下圖,此時以祖父節點為軸進行左旋,將祖父節點變為紅色,newNode變為黑色。

4. 刪除

分情況討論(和插入一樣,以下情況基本都是為了保持上文所講的的紅黑樹特性4和特5)

  1. 如下圖,如果待刪除節點B有兩個非空的孩子節點,轉化成待刪除節點只有右孩子(或沒有孩子)的情況,習慣性選取待刪除節點右子樹最小節點E替換待刪除節點(只是值替換,顏色不變),並將待刪除節點變為E。

  1. 根據待刪除節點和唯一子節點顏色,分情況處理:

    1. 自身O是紅色,子節點N是黑色,直接刪除。

    2. 自身O是黑色,子節點N是紅色,直接刪除將子節點N變為黑色。

    3. 自身O是黑色,子節點N不存在(不存在即子節點為空黑色節點,也可以用來判斷)也是黑色,較為複雜,先刪除,再分情況討論:

      1、N是根節點,則不需要調整。

      2、如下圖,N的父親、兄弟、侄子都是黑色,則將兄弟變為紅色,父親視作N,進行遞迴處理。

  					  3、(**存在映象**)N的兄弟節點是紅色,且N為父親節點左兒子,則以父親節點為軸左旋(否則右旋),並將旋轉後N的祖父節點變為黑色,N的父節點變為紅色,進入情況4,5或6.

  					  4、N的父親節點是紅色,兄弟和侄子節點是黑色,父親節點變為黑色,兄弟節點變為紅色。

  					  5、(**存在映象**)N的父節點顏色隨意,兄弟節點為父節點黑色右孩子,左侄子節點為紅色,右侄子節點為黑色,以兄弟節點為軸進行右旋,將旋轉後N的兄弟節點變為黑色,N的右侄子節點變為紅色,進入情況6

  					  6、(**存在映象**)N的父節點隨意,兄弟節點為父節點的黑色右兒子,右侄子節點為紅色,以N的父節點為軸進行左旋,左旋後的N的祖父節點變為父節點顏色,父節點變黑,叔叔節點變黑。

測試

原樹(上右下左)

刪除53

刪除23

刪除54

新增67

程式碼:

https://github.com/DEUSJIN/RBTree

相關文章