最近組內定個規矩,每周分享一個算法,上周是第一周,分享的是紅黑樹,下面是自己學習總結的,感覺網上的都不是特別清楚,要么是寫的特別復雜,沒有一點條理。
一、紅黑樹性質
1.每個結點要么是紅的要么是黑的
2.根結點是黑的
3.每個葉結點(葉結點即指樹尾端NIL指針或NULL結點)都是黑的
4.如果一個結點是紅的,那么它的兩個兒子都是黑的
5.對於任意結點而言,其到葉結點樹尾端NIL指針的每條路徑都包含相同數目的黑結點
總結:平衡狀態下紅黑樹要么單支黑-紅,要么有兩個子節點
二、復雜度
O(lgn)
三、結點插入
將一個節點插入到紅黑樹中,需要執行哪些步驟呢?首先,將紅黑樹當作一顆二叉查找樹,將節點插入;然后,將節點着色為紅色;最后,通過旋轉和重新着色等方法來修正該樹,使之重新成為一顆紅黑樹。
1.將插入的節點着色為紅色,不會違背"特性(5)"!少違背一條特性,就意味着我們需要處理的情況越少。接下來,就要努力的讓這棵樹滿足其它性質即可;滿足了的話,它就又是一顆紅黑樹了
2.對於"特性4",是有可能違背的!
總之:新插入的結點是紅色!
3.插入的5種情況:
(1)如果插入的是根結點,由於原樹是空樹,此情況只會違反性質2,因此直接把此結點塗為黑色;
(2) 如果插入的結點的父結點是黑色,由於此不會違反性質2和性質4,紅黑樹沒有被破壞,所以此時什么也不做。
(3) 如果當前結點的父結點是紅色且祖父結點的另一個子結點(叔叔結點)是紅色;
解決: 將當前節點的父節點和叔叔節點塗黑,祖父結點塗紅,把當前結點指向祖父節點,從新的當前節點重新開始算法。
以下(4)(5)都以左孩子為例,右孩子進行對稱操作即可
(4)當前節點的父節點是紅色,叔叔節點是黑色,當前節點是其父節點的左孩子;
解決: 父節點變為黑色,祖父節點變為紅色,在祖父節點為支點右旋。
(5)當前節點的父節點是紅色,叔叔節點是黑色,當前節點是其父節點的右子;
解決:當前節點的父節點做為新的當前節點,以新當前節點為支點左旋。問題轉為(4)
總結:整個過程就是解決以上幾個問題,關鍵是整個過程要更新當前節點是哪個結點
四、結點刪除
需要執行的操作依次是:首先,將紅黑樹當作一顆二叉查找樹,將該節點從二叉查找樹中刪除;然后,通過"旋轉和重新着色"等一系列來修正該樹,使之重新成為一棵紅黑樹。
待刪除的節點按照兒子的個數可以分為三種:
1.刪除葉結點(沒有子結點)
(1)如果葉結點為紅色,直接刪除
(2)如果葉結點為黑色,兄弟結點沒有子結點
解決: 兄弟節點B繪為紅色,父節點P繪為黑色。
注意:之后操作的結點全為左孩子,右孩子進行對稱操作即可
(3)葉結點為黑色,兄弟結點有一個孩子不為NIL。若這個孩子為右孩子。
解決:將B的這個右孩子繪為黑色,B繪為其父節點P原來的顏色,P繪為黑色,然后對P進行一次左旋轉。
(4)葉結點為黑色,兄弟結點有一個孩子不為NIL,若這個孩子為左孩子。
解決:將B的這個左孩子繪為黑色,B繪為紅色,然后對B進行一次右旋轉,問題轉化為右孩子的情況。
(5)葉結點為黑色,兄弟結點有兩個孩子。 若兄弟結點(B)為紅色,則B的兩個孩子一定為黑色。
解決:將B繪為黑色,B的左孩子繪為紅色,然后對P(父結點)進行一次左旋轉。
(6)葉結點為黑色,兄弟結點(B)有兩個孩子。 若B為黑色,則B的兩個孩子一定為紅色。
解決:將B的父節點P繪為黑色,B的右孩子繪為黑色,B繪為其父節點P原來的顏色,然后對P進行一次左旋轉。
2.刪除結點有一個外部結點(有一個子結點, 這個結點C一定是紅色節點,否則從D到各個NIL節點的路徑上的黑色節點數目就會不同)
解決:交換D(刪除結點)和C(子結點)的內容(顏色保持不變),被刪除節點變為C,問題轉化為被刪除節點的兩個孩子都為NIL的情況。重新查看樹是否滿足紅黑樹。
3.刪除結點有兩個外部結點(有兩個子結點)
解決:按照二叉查找樹刪除節點的方法找到D的后繼節點S,交換D和S的內容(顏色保持不變),被刪除節點變為S,如果S有不為NIL的節點,那么繼續用S的后繼節點替換S(此過程可能是一級一級找,也可能是直接找左子樹的最大值,取決於本來要刪除的結點和實際刪除結點的值的大小,要刪除的結點比實際刪除的結點小,一級一級找,否則相反),直到被刪除節點的兩個孩子都為NIL,問題轉化為被刪除節點D的兩個孩子都為NIL的情況。
其中的左旋右旋其實也很簡單,有不清楚的大家上網查查,此處不再詳細敘述了。
五、應用場景
1.著名的linux進程調度Completely Fair Scheduler,用紅黑樹管理進程控制塊
2.epoll在內核中的實現,用紅黑樹管理事件塊
3.nginx中,用紅黑樹管理timer等
4.Java的TreeMap實現
5.廣泛用在C++的STL中。map和set都是用紅黑樹實現的。
六、其他
從頭到尾的插入和刪除操作案例插圖:
http://blog.csdn.net/v_july_v/article/details/6284050
nginx 紅黑樹的實現(c實現)
http://blog.csdn.net/liuxuejiang158blog/article/details/21417145
c的紅黑樹實現
http://www.cnblogs.com/skywang12345/p/3624177.html#a3
php的紅黑樹實現
http://www.zhangley.com/article/php_rbtree/