《DSAA》 12.2.3 紅黑樹的自頂向下刪除

當初自學圍棋的時候背過一些定式,一般定式都比較容易,從開始到結束用不了幾個回合。直到有一天遇到了像妖刀,大雪崩,大斜這樣的大型定式,變化極爲繁複,一個定式擺下去能佔滿1/4個棋盤,這個要掌握就非常困難了。
如果把算法類比爲圍棋的佈局,數據結構類比爲定式的話,紅黑樹無疑就是一個大型定式。個人感覺它的搜索和插入什麼的還算簡單,而且原書也給出了實現。但難就難在刪除,偏偏書裏只講了大致思路,看着非常費解,然後就大筆一揮留作練習了,作者不負責任得令人髮指。只好硬着頭皮上了,經過一番掙扎,編碼測試居然還是通過了。回頭看看其實書上講的還是蠻精確的,也沒像當初覺着那麼複雜,主要它還是有一個模式:在每一次迭代開始時,父親得是紅色的,然後再設法把當前節點變成紅色。
爲什麼要把當前節點變成紅色?因爲黑色節點不好刪除,一刪很容易就亂套了。
又爲什麼父親會是紅色的?因爲父親是上一個當前節點,咱就是從它那兒過來的。
目前看起來還比較簡單,麻煩在於有很多例外情況:
首先根就是黑色的。不過書裏自有辦法:引入一個假根,令原樹根成爲它的右子樹,把假根塗紅了就行,這個算是對付過去了。
接着上還有兩個例外,至於爲什麼會出現這兩個例外,我們稍後再說:
1) 迭代開始時,父親和兄弟是黑的,當前節點是紅的,這種情況不用處理,反正當前節點已經是紅的,相當於本輪已經處理完了,可以進入下輪迭代。
2)迭代開始時,父親和當前節點是黑的,兄弟是紅的。這種情況必須要使出旋轉大法,旋轉兄弟和父親,兄弟變黑升兩輩成了祖父不提,關鍵是父親變紅了,於是我們又回到了正確的軌道上,現在可以設法把當前節點變紅。
下面介紹處理過程,這裏會出現了兩個大分支:
1)當前節點有兩個黑兒子,對付這種情況有一個固定的旋轉套路,它通過上下翻轉或左右旋轉可以把當前節點也變紅,同時又能保持紅黑樹的特性。這個其實是重點,但因爲書上說的比較清楚,這裏就不再贅述了。
2)當前節點至少有一個紅兒子,如果迭代的下一輪會落到那個紅兒子上,則將在那輪出現上文提到的第一種例外。如果情況相反下一輪落到黑兒子上,則將在那輪出現第二種例外,不過本輪中都不需要做什麼處理,也就是不需要把當前節點變紅。
這裏又有問題,在第二個分支中,當前節點並沒有變紅,如果它就是所要刪除的節點怎麼辦?
這就得回頭再說一說刪除的方法,實際上我們並不刪除中間節點,而只是用其右子樹的最小節點或者左子樹的最大節點來替換它,當把這個值替換以後,下面目標就變成了要刪除那個用來替換的節點,然後我們就針對這個替死鬼繼續向下搜索,也許替死鬼還會更新多次,直到它變成一片樹葉,等我們找到它後才把它放心地幹掉。
這裏還有一個技巧,當一個節點沒有兒子(或者只有一個兒子)時,之用的並不是空指針,而是指向一個全局的空節點,該節點的顏色爲黑。所以當前節點是葉子時,左右兒子都是空節點,所以我們一定可以它變紅了。
最後提一句,如何校驗一顆紅黑樹呢?雖然是無關主題。但在測試的時候必需這樣一個方法,否則樹一多用肉眼看肯定喫不消。
以下演示是一顆樹的逐節點刪除過程,和上一篇裏的伸展樹比較,可以看出紅黑樹的平衡性要好很多,果然是名不虛傳:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章