學習過2-3樹以後就知道應怎樣去理解紅黑樹了,若是直接看「算法導論」裏的紅黑樹的性質,是看不出因此然。咱們也看看一顆二分搜索樹知足紅黑的性質:html
1.每一個節點或是紅色的,或是黑色的;java
2.根節點是黑色的;算法
3.每一個葉子節點(NIL)是黑色的;segmentfault
4.若是一個節點是紅色的,則它的兩個子節點都是黑色的;ide
5.對每一個節點,從該節點到其全部後代葉子節點的簡單路徑上,均包含相同數目的黑色節點。學習
若是說前面4個還算理解,那第5個性質又是怎麼去理解呢?此時咱們藉着2-3樹去理解基本的紅黑樹,固然我會在後幾篇文章介紹2-3-4樹以及基於2-3-4樹的紅黑樹。動畫
拋開上面二分搜索樹知足紅黑的性質,咱們知道2-3樹不是二叉樹,咱們把它轉換成一顆二叉樹,2-節點很好轉,3-節點轉二叉卻有兩種,以下圖:spa
紅黑是指被指向節點的連接顏色,對於一顆2-3樹,由於3-節點的存在有不少不一樣的二叉樹的表示,因此咱們只考慮左傾的狀況。3d
紅黑樹的定義是含有紅黑連接並知足下列條件的二分搜索樹:htm
1.紅連接均爲左鏈接;
2.沒有任何一個節點同時和兩條紅連接相連;
3.該樹是完美黑色平衡的,即任意空連接到根節點的路徑上的黑連接數量相同(和2-3樹等價的,任意節點到其葉子節點的高度都是相同的)。
由於2-3樹不存在永久的4-節點,4-節點終歸要分解的(在2-3-4樹中,爲了更好地插入和刪除,4-節點只存在於葉子節點,非葉子節點和2-3樹同樣的),因此在2-3樹中沒有任何一個節點能同時和兩條紅連接相連。對於第3條,2-3樹自己是絕對平衡的,將3-節點轉成二叉只增長了左紅連接,其餘黑連接沒有什麼變化,依然是黑色平衡的。
查找命中和二分搜索樹同樣,從根節點開始,若是查找命中則返回,不然比它小的進行左遞歸查找,比它大的進行右遞歸查找,直到查找爲空。
寫插入元素和刪除元素以前,仍是要先介紹一下旋轉和顏色轉換。
在插入或者刪除操做中可能會出現右傾或者兩條連續的紅連接,在向上變換的過程當中(恢復)都要調整爲左傾。
假設有一條紅色的右連接須要轉爲左連接,以下圖所示:
這個操做叫作左旋轉,右連接變成左連接,意味着被紅連接指向的節點會變成紅色,根節點默認是黑色。
右旋轉也同樣,不過在左傾紅黑樹中,只有出現兩條連續紅色的左鏈接纔會進行右旋轉,以下圖:
顏色轉換是用在臨時4-節點上的,無論是向下變換仍是向上變換。
插入元素也須要先進行查找命中,查找未命中則在此節點(NIL)插入一個元素,是在紅黑樹底下插入一個紅色節點,插入元素默認是紅色節點。
若是紅黑樹目前是一顆空樹,能夠直接存儲一個元素做爲節點,而後該節點變成黑色。若是不是一顆空樹,插入元素分兩種狀況:向2-節點插入新元素和向3-節點插入新元素。
向2-節點插入新元素很簡單,若是新元素小於父節點的元素,直接插入紅色的節點便可;若是新元素大於父節點的元素,則產生一個紅色右連接,插完以後進行向上變換,在向上變換的過程當中(修復紅黑樹的性質)須要進行左旋轉,將右連接變成左連接,知足左傾紅黑樹的性質。
1.新元素小於3-節點最小值
2.新元素位於3-節點最小值和最大值之間
3.新元素大於3-節點最大值
插入元素只有向上變換的過程,目的是爲了知足紅黑性質。
刪除元素既有向下變換也有向上變換:向下變換是爲了樹底下有一個被紅連接指向的節點能夠被刪除,不影響黑色平衡;向上變換是爲了修復基於2-3樹的左傾紅黑樹。
刪除元素有4個原則:
1.刪除元素的當前節點不能是2-節點;
2.向下變換不爲2-節點;
3.從樹底部刪除節點;
4.向上變換,消除右傾和4-節點。
刪除元素藉鑑了以前學的二分搜索樹刪除元素的思想,二分搜索樹刪除元素分爲刪除最小元素、刪除最大元素和刪除任意元素三種狀況:刪除最小元素是一直遞歸它的左孩子,直到左孩子爲空才進行刪除;刪除最大的元素則相反;若是是刪除任意的元素須要進行命中查找,找到了就取右子樹的最小值替換掉待刪除元素,而後進行右子樹的刪除最小元素。
紅黑樹刪除元素也是同樣的,不過是多了向下變換和向上變換的過程。由於是左傾紅黑樹,刪除最小元素是最合適的。
「算法4」裏的紅黑樹介紹了刪除最小鍵這一小節,雖沒有很詳細地介紹,但給出了沿着左連接向下變換的三種狀況:
1.若是當前節點(父節點位置)的左子節點不是2-節點,完成;
2.若是當前節點(父節點位置)的左子節點是2-節點而左子節點的兄弟節點不是2-節點,則左子節點借它的兄弟節點的一個鍵過來;
3.若是當前節點(父節點位置)的左子節點和左子節點的兄弟節點都是2-節點,將左子節點、當前節點和左子節點的兄弟節點合併成一個臨時的4-節點,使當前節點由3-節點變成2-節點或則4-節點變成3-節點。
刪除最大節點思路也是同樣的,不過這是左傾紅黑樹,對刪除最大節點益處不大,甚至向下轉換的時候左傾調整爲右傾,向上轉換balance還要將右傾調整爲左傾。
在前面學習了刪除最小節點,刪除任意節點天然就很簡單了。咱們若是要刪除一個節點,首先進行命中查找,查找到這個待刪除元素,將右子樹的最小值替換掉這個待刪除元素,指向待刪除節點的連接顏色不能被改變。而後進行右子樹的刪除最小元素。
在命中查找過程當中,須要沿着左連接或沿着右連接進行向下轉換。前面刪除最小元素就是沿着左連接向下轉換的。
沿着右連接向下轉換也分三種狀況:
1.若是當前節點(父節點位置)的右子節點不是2-節點,將左傾轉換成右傾;
2.若是當前節點(父節點位置)的右子節點是2-節點而右子節點的兄弟節點不是2-節點,則右子節點借它的兄弟節點的一個鍵過來;
3.若是當前節點(父節點位置)的右子節點和右子節點的兄弟節點都是2-節點,將右子節點、當前節點和右子節點的兄弟節點合併成一個臨時的4-節點,使當前節點由3-節點變成2-節點或則4-節點變成3-節點。
閱讀原文可查看算法4裏的RedBlackTree.java源碼
喜歡本文的朋友,歡迎關注公衆號「算法無遺策」,收看更多精彩內容