和上篇介紹的 AVL 樹同樣,紅黑樹也是一種自平衡的二叉查找樹,經過以前的學習咱們知道,自平衡的二叉查找樹是高效的,它能夠在時間複雜度爲 O(log n)下作查找、插入和刪除。紅黑樹具有以下性質:git
下面是紅黑樹的例子:github
紅黑樹複雜的地方主要在於對其執行增刪操做會破壞上面的紅黑屬性,所以要有相應的機制恢復。這裏的恢復機制除了在介紹 AVL Tree 時講到的旋轉,還多了一種從新着色
,顧名思義,把紅色變成黑色,黑色變成紅色便可,在下面的介紹中會具體講到。學習
先看下紅黑樹插入的狀況,紅黑樹的插入思路是先按照二叉查找樹插入的操做(具體思路請看這篇)插入節點,再經過從新着色或者旋轉的方法恢復紅黑屬性。規定了新增的節點顏色爲紅色
(若是設爲黑色,就會致使根到葉子的路徑上有一條路上,多一個額外的黑節點,這個是很難調整的。)可是設爲紅色節點後,可能會致使出現兩個連續紅色節點的衝突,所以插入操做主要是解決上面的紅黑屬性 2 。下面爲總結的 4 種插入情景及對應調整 「套路」,插入時檢查叔叔
的顏色,假設 z 爲新插入的節點,3d
基於這 4 點舉例分析紅黑樹插入的狀況,先插入節點 15:code
因爲 15 是根節點,知足套路 1 ,所以將其由紅色置爲黑色;再相繼插入 五、1:cdn
插入節點 1 後知足套路 3 ,這裏先對節點 15 右旋,再從新着色即恢復紅黑屬性。blog
再看下一個稍微複雜的例子,對下面這棵紅黑樹插入節點 10:get
此時知足套路 4,將父節點 15 右旋:it
此時知足套路 3,左旋爺爺節點 8 ,再對 8 和 12 從新着色即恢復紅黑屬性。io
與插入相同,紅黑樹的刪除思路是先按照二叉查找樹刪除的操做(具體思路請看這篇)刪除節點,再經過從新着色或者旋轉的方法恢復紅黑屬性。插入操做主要是違反了上面提到的紅黑屬性 2 ,而刪除操做是違反了紅黑屬性 3 。在插入操做中,根據叔叔的顏色來選擇適當的 「套路」 ,在刪除操做中,主要依據兄弟
的顏色 。設 X 是要刪除的節點,Y 是替換樹中 X 的節點,S 爲 X 的兄弟。
I. X 和 Y 中有一個爲紅色 -> 將 Y 置爲黑色
。
來看下例子,在下面的紅黑樹中要刪除節點 30 :
再看下面這個例子,在下面的紅黑樹中要刪除節點 30 :
II. X 和 Y 都是黑色。
接下來的情景比較特殊,引入雙黑色的概念。雙黑色是指:當黑色節點被刪除並被黑色孩子替換時,孩子被標記爲雙黑色。
被標記爲雙黑色的節點,所在的路徑黑色節點數量加 1 。共有如下這麼幾種狀況:
a) 兄弟 S 是黑色,S 的孩子至少有一個是紅色
,假設 R 是 S 的紅色子節點,根據 R 和 S 的位置能夠分爲下面四種狀況:
a1 . 右右:S 是其父親的右節點,R 是 S 的右節點。
a2 . 右左:S 是其父親的右節點,R 是 S 的左節點。
a4 . 左右:S 是其父親的左節點,R 是 S 的右節點。
舉個例子,在下面的紅黑樹中刪除節點 5 :
刪後以下:
b) 兄弟 S 是黑色,S 的孩子都是黑色。
解決方案:若是父節點爲黑色,則置爲雙黑色,;若是父節點爲紅色,則置爲黑色;S 置爲紅色;若根節點爲雙黑色時,置爲黑色。
舉個例子,在下面的紅黑樹中刪除節點 10 :
首先經過二叉查找樹的遍歷方法找到 10 ,遍歷右子樹,用 20 代替,再刪除 20 ,刪完以下:
上面的圖偷懶了,咱們知道空節點默認是黑色的,因此完整的圖應該是這樣的:
此時不知足紅黑屬性 3 ,從根節點 10 到其餘空葉子節點通過的黑色節點數量爲 3 ,而到 z 這條路徑通過的黑色節點數量爲 2 ,將 z 置爲雙黑色,這樣就平衡了:
接下來就是解決雙黑色的問題了,將 38 置爲紅色,將 30 置爲黑色即恢復紅黑樹 :
下面的紅黑樹中刪除節點 10
刪後以下:
將 40 置爲紅色,並把 30 置爲雙黑色:
因爲節點 30 是根節點,因此直接去掉節點 30 外圈加的黑色:
c) 兄弟 S 是紅色。
按照 S 的位置又分爲下面兩種狀況
c1. 右側:S 是右子節點:
c2. 左側:S 是左子節點:
Enjoy –☺