1.紅黑樹的意義node
[1]二叉查找樹在極端的插入狀況下,操做時間複雜度會變爲O(n),可是平衡二叉樹能夠一直維持在O(lg(n))。所以平衡二叉查找樹的效率很高,紅黑樹是一種自平衡二叉查找樹的實現方式,這即是紅黑樹的意義。linux
2.紅黑樹性質spa
[1]節點是紅色或黑色。
[2]根節點是黑色。
[3]每一個葉節點(NIL節點,空節點)是黑色的。
[4]每一個紅色節點的兩個子節點都是黑色。(從每一個葉子到根的全部路徑上不能有兩個連續的紅色節點)
[5]從任一節點到其每一個葉子的全部路徑都包含相同數目的黑色節點。code
3.變色、左旋和右旋blog
[1]變色, 目的是進行操做後能夠(更趨近於)保持紅黑樹的性質。遞歸
[2]左旋和右旋是變動節點在樹中的位置,目的是進行這些操做後能夠(更趨近於)保持紅黑樹的性質。源碼
4.刪除操做class
紅黑樹的刪除和二叉查找樹的刪除操做是同樣的,只是多了一個修復平衡的流程。 效率
總體流程:首先按照二叉查找樹的方式刪除節點。以後判斷釋放節點的顏色,若是是紅色,則結束,不然進入修復流程,修復流程就是一個狀態機,直到走到完成狀態。二叉樹
[1]按照二叉查找樹的刪除流程:
[3]修復(狀態機),循環執行如下操做:
1)若是當前節點是紅色,則把當前節點塗黑,操做結束。
2)若是當前節點是黑色,且兄弟節點是紅色,則進行操做:兄弟節點塗黑,父節點塗紅,對父節點進行左旋。(此時,當前節點的父節點沒變,可是兄弟節點變爲黑色)。
3)若是當前節點是黑色,且兄弟節點是黑色,且兄弟節點的兩個子節點都是黑色,則進行操做:兄弟節點塗紅,將父節點做爲當前節點(附帶的操做就是更新父節點爲以前節點的祖父節點)。
4)若是當前節點是黑色,且兄弟節點是黑色,且兄弟節點的右子節點是黑左子節點是紅,則進行操做:兄弟節點塗紅,兄弟左子節點塗黑,對兄弟節點進行右旋。(此時,當前節點的父節點沒變,可是兄弟節點的右子節點變爲紅色)。
5)若是當前節點是黑色,且兄弟節點是黑色,且兄弟節點的右子節點是紅左子節點任意,則進行操做:兄弟節點的顏色塗成父節點的顏色,父節點塗黑,兄弟節點的右子節點塗黑,對父節點進行左旋,將根節點塗黑,操做結束。
以上是當前節點是父節點左子節點的狀況,若是是右子節點,只是作了對稱處理(例如,對某個狀態,做爲左子節點時作左旋,而做爲右子節點作右旋)。
5.插入操做
紅黑樹的刪除和二叉查找樹的插入操做是同樣的,只是多了一個修復平衡的流程。
總體流程:首先按照二叉查找樹的方式插入節點,把插入節點塗紅。以後進入修復流程,修復流程就是一個狀態機,直到走到完成狀態。最後把根節點塗黑。
[1]按照二叉查找樹的插入流程:小於根的往左子樹遞歸插入,不然往右子樹遞歸插入。插入的節點一定是插到最下面那一層,不會插入到樹的中間位置。
初始把剛插入的節點塗紅(塗紅不會影響規則5,所以只須要處理更少的條件),把剛插入的節點做爲當前節點。
[2]修復(狀態機),循環執行如下操做:
1)若是當前節點的父節點是空,狀態機完成。
2)若是當前節點的父節點是黑色,狀態機完成。
3)若是當前節點的父節點是紅色,叔叔節點是紅色,則執行操做:將當前節點的父節點塗黑,叔叔節點塗黑,祖父節點塗紅,再將祖父節點做爲當前節點。
4)若是當前節點的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的右子節點,則執行操做:對當前節點的父節點執行左旋,並把當前節點的父節點做爲當前節點(附帶更新當前節點的父節點(就是以前的節點))。
5)若是當前節點的父節點是紅色,叔叔節點是黑色,且當前節點是其父節點的左子節點,則執行操做:對當前節點的父節點塗黑,祖父節點塗紅,對祖父節點執行右旋。
最後把根節點塗黑,結束。
以上是當前節點是父節點左子節點的狀況,若是是右子節點,只是作了對稱處理(例如,對某個狀態,做爲左子節點時作左旋,而做爲右子節點作右旋)。
6.總結
[1]紅黑樹的插入和刪除和二叉查找樹的方式是同樣的,以後多了一個修復流程,主要就是修復流程的狀態機,對於某一個狀態來講,須要進行一系列的操做,進行這個操做的目的是爲了進入下一個狀態,下一個狀態確定更趨近於樹的平衡。
[2]關於變色、左旋和右旋,這些操做的目的是爲了讓樹的當前狀態更趨於平衡,這個也是處理紅黑樹的關鍵,即何時須要變色、旋轉,爲什麼變色、旋轉後能夠更趨近於平衡,這個也須要在實踐中熟練。
[3]對於插入修復狀態機的第4個狀態說明:"對當前節點的父節點執行左旋",這個操做結束後,當前節點和父節點的位置會互換,所以把父節點做爲當前節點後,當前節點的父節點就是以前的節點,代碼就是:
register struct rb_node *tmp; __rb_rotate_left(parent, root); //對父節點左旋 tmp = parent; // parent = node; //父節點做爲當前節點,同時更新當前節點的父節點 node = tmp; //
[4]代碼,參照linux內核紅黑樹源碼。