徹底搞懂紅黑樹
紅黑樹性質
1、每個結點或是紅色的,或是黑色的
2、根節點是黑色的
3、每個葉結點(NIL)是黑色的
4、如果一個節點是紅色的,則它的兩個兒子都是黑色的。
5、對於每個結點,從該結點到其葉子結點構成的所有路徑上的黑結點個數相同。
和AVL樹的比較
AVL樹是一棵嚴格的平衡樹,它所有的子樹都滿足二叉平衡樹的定義。因此AVL樹高被嚴格控制在XXX,因此AVL樹的查詢比較高效。但AVL樹插入、刪除結點後旋轉的次數比紅黑樹多。
紅黑樹用非嚴格的平衡來降低插入刪除時旋轉的次數。
因此,如果你的業務中查詢遠遠多於插入、刪除,那選AVL樹;
如果查詢、插入、刪除頻率差不多,那麼選擇紅黑樹。
插入過程
預設插入的結點為紅色。為何?
因為紅黑樹中黑節點至少是紅節點的兩倍,因此插入節點的父節點為黑色的概率較大,而此時並不需要作任何調整,因此效率較高。
1. 父為黑
插入後無需任何操作。由於黑節點個數至少為紅節點的兩倍,因此父為黑的情況較多,而這種情況在插入後無需任何調整,這就是紅黑樹比AVL樹插入效率高的原因!
2. 父為紅
父為紅的情況破壞了紅黑樹的性質,此時需要根據叔叔的顏色來做不同的處理。
叔叔為紅
此時很簡單,只需交換爸爸、叔叔和爺爺的顏色即可。
此時若爺爺節點和太爺爺節點顏色相同,再以爺爺節點為起始節點,進行剛才相同的操作,即:根據爺爺的兄弟顏色做相應的操作。叔叔為黑
此時較為複雜,分如下四種情況:
a)爸爸在左、叔叔在右、我在左
以爸爸為根節點,進行一次R旋轉。
b)爸爸在左、叔叔在右、我在右
先以我為根節點,進行一次L旋轉;
再以我為根節點,進行一次R旋轉。
c)叔叔在左、爸爸在右、我在左
先以我為根節點,進行一次R旋轉;
再以我為根節點,進行一次L旋轉。
d)叔叔在左、爸爸在右、我在右
以爸爸為根節點,進行一次L旋轉。
刪除過程
二叉搜尋樹的刪除
若刪除二叉搜尋樹的節點A,實際上刪除的是二叉搜尋樹中序遍歷的前驅節點,注意:
1. 這個被刪除節點要麼就是一個葉子節點,
2. 要麼有且僅有一個左孩子
然後將孩子頂替它原來的位置,最後將被刪的節點值覆蓋待刪除的那個節點A。
紅黑樹按照二叉搜尋樹的方式刪除節點,之後再進行相應的旋轉操作,使得刪除後的樹仍然是一棵紅黑樹。
定義
- 待刪除節點:要刪除的那個節點
- 實際刪除節點:待刪除節點的中序遍歷前驅
紅黑樹實際刪除節點的性質
- 實際刪除節點要麼是葉子節點,要麼有且僅有一個左孩子;
- 若為葉子節點,必為紅色;
- 若實際刪除節點還有孩子,則該必為左孩子;
a)若左孩子為紅色,則實際刪除節點必為黑色;
b)若左孩子為黑色,則實際刪除節點紅黑均可以。
約定
- 藍色箭頭:表示判定點
- 在刪除操作開始前,藍色箭頭首先指向實際刪除節點。
- 『實際刪除節點』在圖中以『父』表示。
旋轉過程開始:
1. 父為紅色(待刪節點為葉子)
直接刪除父節點即可:
2. 父為黑 子為紅(待刪節點為黑、待刪節點子節點為紅+左孩子)
用子節點覆蓋父節點,並保持父節點的顏色:
3. 父為黑 子為黑(待刪節點和子節點均為黑)
3.1. 叔叔為紅
PS:叔叔為紅,則爺爺必為黑!
父在左 叔在右
a)子節點覆蓋父節點
b)進行一次左旋
父在右 叔在左
a)子節點覆蓋父節點
b)進行一次右旋
3.2. 叔叔為黑
PS:叔叔、爸爸都為黑,那爺爺顏色就不確定了!
祖父紅 兩個侄子黑
以下兩種情況操作一致:
1.子覆蓋父(刪除)
2.交換祖父和叔叔的顏色。a)父在左 叔在右
b)父在右 叔在左
同上。祖父黑 兩個侄子黑
以下兩種情況操作一致:
1. 祖父染成子節點的顏色;
2. 子節點染成黑色;
3. 叔叔染成紅色
a)父在左 叔在右
b)父在右 叔在左祖父顏色隨意 至少有一個紅侄
a)紅侄為左左(叔左、紅侄左)
1. 紅侄進行一次右旋
2. 紅侄染成黑色
3. 交換叔叔和祖父的顏色
b)紅侄為左右(叔左、紅侄右)
1. 紅侄進行一次右旋+左旋
2. 紅侄染成父節點顏色;
3. 父節點染成黑色
c)紅侄為右左(叔右、紅侄左)
1. 紅侄進行一次右旋+左旋
2. 紅侄染成父節點顏色;
3. 父節點染成黑色;
d)紅侄為右右(叔右、紅侄右)
1. 紅侄進行一次左旋
2. 叔叔染成父節點顏色;
3. 紅侄染成黑色;