日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
他一口氣寫出了這7k字的紅黑樹總結!看過的都說好??!

紅黑樹是一種很經(jīng)典的數(shù)據(jù)結構,它可以在O(log n)時間內(nèi)做查找,插入和刪除。所以倍受關注。但是一直以來很多Java程序員對他都不是很重視,直到在JDK 1.8中,HashMap會將其鏈表轉換成紅黑樹,此后,很多人就開始重新學習紅黑樹的有關知識。

作者在學習紅黑樹時,查閱了很多資料都沒有找到解釋的特別清楚的,于是自己總結了這一篇文章,總字數(shù)近7k,而且繪制了很多圖,希望可以讓大家更容易理解。

1. 定義

紅黑樹是Avl樹的一個變種,它也是在二叉查找樹的基礎上添加平衡條件,只是它對平衡條件的描述不像AVl樹那樣直接,而是轉化成對節(jié)點顏色規(guī)則的描述。

顏色規(guī)則:

  1. 對于任意節(jié)點,要么是紅色,要么是黑色;
  2. 根節(jié)點是黑色的;
  3. 如果一個節(jié)點是紅色的,那么它的子節(jié)點必須是黑色的(即不能有兩個連續(xù)的紅色節(jié)點);
  4. 任意節(jié)點到其下面各個空結點(后面稱為nil節(jié)點,并約定其顏色為黑色)的路徑上都包含相同數(shù)目的黑色節(jié)點(稱為黑高);

通過對任何一條從根到空節(jié)點的路徑上各個結點的顏色進行約束,紅黑樹可以確保沒有一條路徑會比其他路徑長出2倍,因而紅黑樹是近似平衡的。

 

2. 分析實現(xiàn)

為了便于處理紅黑樹代碼中的邊界條件,使用兩個標記節(jié)點header和nil來充當哨兵,它們與樹中的普通節(jié)點有相同的屬性,顏色設為黑色。將header的值設為負無窮,因此它的右子節(jié)點就是真正的根,在對樹進行遍歷時我們可以用header作為起點。nil的值可以為任意值,將它作為所有空節(jié)點的統(tǒng)一引用, 即讓所有樹葉的左右子節(jié)點都指向nil,那么在遍歷時就可以將nil視為結束的標志。

紅黑樹也是一顆查找二叉樹,所以它的基本操作與查找二叉樹一致,區(qū)別也在于插入和刪除后的平衡恢復。只是實現(xiàn)平衡時的目標就是滿足它對顏色規(guī)則的定義,至于樹的平衡與否已經(jīng)由規(guī)則本身去保證。

2.1. 插入

與二叉查找樹一樣,插入節(jié)點其實就是添加一個樹葉,主要問題是在添加結束時可能要做一些調(diào)整來保證紅黑樹的規(guī)則不被破壞。

不過,根據(jù)規(guī)則4, 可以知道,在插入之前任意節(jié)點到其下面各個nil的路徑上都包含相同數(shù)目的黑節(jié)點數(shù),如果能保證在插入節(jié)點前后父節(jié)點parent或者祖父節(jié)點grand到其下面nil的路徑上的黑節(jié)點數(shù)不變, 即保證parent或者grand的黑高不變,那么就可以保證紅黑樹的規(guī)則不被破壞,這樣就可以將平衡操作時需要考慮的范圍縮小到grand。

由于插入紅色節(jié)點不會影響路徑上的黑節(jié)點數(shù),因此就先將待插入的節(jié)點涂成紅色,如果parent是黑色,那么插入直接完成。如果parent是紅色,那么插入之后將違反規(guī)則3, 這時再做一些調(diào)整。

先分析一下插入之前的可能情形,根據(jù)規(guī)則3,如果parent是紅色,那么可以斷定grand以及parent的另一個子節(jié)點一定是黑色。不僅如此,因為插入的是樹葉節(jié)點在之前一定是nil, 那么parent的另一個子節(jié)點必然也是nil,否則插入之前parent就違反了規(guī)則4。

再看parent的兄弟節(jié)點,如果它是黑色的,那么它一定也是nil節(jié)點;如果它是紅色的,那么它的兩個子節(jié)點一定都是nil節(jié)點,否則插入之前grand就違反了規(guī)則4。

所以,如果parent是紅色,那么我們可以完整地畫出插入之前的所有可能情況,一共有4種,其中待插入節(jié)點的位置就是圖中parent下面的兩個nil之一。

可以看出,1和2,3和4分別是對稱的兩種情況,區(qū)別在于parent與grand的大小關系,其實可以概括為parent的兄弟節(jié)點uncle是黑色還是紅色的兩種情況。

1. 如果parent為紅色,uncle為黑色

以情況1為例(即parent小于grand):如果current小于parent,那么插入之后,可以將parent和grand的顏色互換,然后將grand右旋,這樣就能保證原來以grand為根的這個子樹的黑高保持不變,也就保證了整棵樹不被破壞。

如果current大于parent,則可以先將parent左旋,然后將current視為parent,再與上面進行相同的操作,即可恢復平衡。

 

2. 如果parent為紅色,uncle為紅色

這時無論怎么旋轉都已經(jīng)解決不了問題,不過可以知道,在插入之前grand到下面各個nil的黑節(jié)點數(shù)為1,因此,只要保證grand的黑高仍然為1就行, 那么,通過將grand與其左右子節(jié)點的顏色進行翻轉便可達到目標。

以情況3為例:

但是,翻轉會使grand變成紅色,這時如果曾祖父也是紅色,那么將違反了規(guī)則3。因此可能需要朝著樹根的方向進行逐層分析,直到不再有兩個相連的紅色節(jié)點或者到達樹根為止,但這顯然會很麻煩。

事實上,由于顏色翻轉的等價性,我們可以在查找插入節(jié)點位置的過程中,通過顏色翻轉來避免掉uncle為紅色的情況,即將顏色翻轉的事情提前做了。

在自上而下的查找過程中,如果看到一個節(jié)點X的兩個子節(jié)點都為紅色,可以使X變成紅色,而兩個子節(jié)點變成黑色(如果X是根,則可以在翻轉之后再將其置為黑色),結果依然滿足紅黑樹的規(guī)則。

只有當X的parent為紅色時,才會破壞紅黑樹的規(guī)則。不過這時可以斷定X的兄弟節(jié)點,X的grand,以及X的uncle都是黑色的(因為如果X的parent和uncle都為紅色, 那么一定會在自上而下的查找和翻轉過程中被過濾掉)。

那么,可以將X視為current,然后與上面parent為紅色,uncle為黑色的情形進行相同的處理。下面通過畫圖來說明一種情形(對稱情形類似處理):

先對X與其子節(jié)點進行顏色翻轉

然后,將X視為之前的current,對parent和grand進行換色和旋轉

 

完成之后,將新的根(即原本grand的位置)視為新的current,然后重新向下遍歷。由于X的孫子節(jié)點之前一定為黑色,而X的兒子節(jié)點在翻轉之后也為黑色,因此在調(diào)整之后, 可以保證在X的下面將有連續(xù)兩層不會出現(xiàn)紅節(jié)點。

所以,盡管旋轉調(diào)整會使得gand的位置變得錯誤,但在接下來的遍歷中,又會立即將grand-parent-current恢復成正確的位置關系。

總結節(jié)點插入問題:首先根據(jù)二叉查找樹的性質(zhì),可以知道插入節(jié)點就是添加樹葉,其次對于紅黑樹而言,插入紅色節(jié)點不會影響路徑上的黑節(jié)點數(shù)。

因此, 我們將插入的節(jié)點視為紅色的樹葉,這時只要考慮插入的紅色樹葉的parent是紅色還是黑色,如果是黑色問題直接解決,如果是紅色,再看uncle是紅色還是黑色。如果uncle是黑色,可以通過變色旋轉解決;如果是紅色,那么通過顏色翻轉也能達到目的,但這會使grand變成紅色,需要進一步考慮曾祖父的顏色問題,將問題放大了。于是考慮在一開始向下的遍歷過程中, 提前翻轉顏色來避免掉parent和unlce同時為紅色的情況。

因此,最終在插入節(jié)點時,實際需要考慮旋轉調(diào)整的情形只有一種,即parent為紅色,uncle為黑色。

2.2. 刪除

對于節(jié)點刪除,大概思路也是先將問題轉化成刪除樹葉來簡化問題,如果是紅色樹葉,則可以直接刪除,如果是黑色樹葉,則再分情形進行討論。

先看下如何將刪除目標轉化成對樹葉的刪除,根據(jù)二叉查找樹的性質(zhì),在刪除節(jié)點時可以用右子樹的最小節(jié)點或左子樹的最大節(jié)點來替換要刪除的節(jié)點,然后刪除子樹中用來替換的那個節(jié)點。

不過在紅黑樹中,為了保證節(jié)點的顏色規(guī)則,替換時將只進行值的替換。其實,根據(jù)紅黑樹的規(guī)則可以得出一個簡單的推論:如果一個樹葉沒有兄弟節(jié)點,那么它一定為紅色,或者說如果一個樹葉為黑色, 則它必然有兄弟節(jié)點。

另外,還可以斷定:對于任意節(jié)點,其右子樹的最小(即最左)節(jié)點最多存在一個紅色右子節(jié)點,其左子樹的最大(即最右)節(jié)點最多存在一個紅色左子節(jié)點。因此,當左子樹的最大節(jié)點或右子樹的最小節(jié)點不是樹葉時,可以繼續(xù)用同樣的思路來轉換要刪除的目標,并且這時可以斷定最后刪除的樹葉一定是紅色。

再來討論刪除黑色樹葉的情形,由于黑色樹葉必然會存在兄弟節(jié)點(樹根除外),因此在下面的討論中首先假設要刪除的黑色樹葉總是在左邊(如果在右邊則對稱處理), 這時可以根據(jù)其兄弟節(jié)點brother和父親節(jié)點parent的顏色來將刪除情形分為3種。下面分別進行畫圖分析(圖中省略掉空節(jié)點nil):

1.parent為紅色,brother為黑色

由于current是樹葉,那么可以斷定brother下面不會再有黑色的后代節(jié)點,至多只能有紅色的兒子節(jié)點,否則parent在刪除前將違反規(guī)則4。

1.1 先看brother沒有兒子的情況,此時看上去比較簡單,直接對parent進行左旋即可解決問題,能夠保證在刪除調(diào)整前后以原parent為根的子樹的黑高不變。

1.2 但是,如果brother有一個紅色左兒子(右兒子沒有影響,因此忽略),那么直接對parent進行左旋,將會造成兩個連續(xù)的紅色的節(jié)點而違反規(guī)則3, 這時需要先將brother右旋,然后再對parent進行換色并左旋來解決。

 

因此,需要根據(jù)brother是否有紅色左兒子將情形1再分為2種子情形來進行處理。

2.parent為黑色,brother為紅色

同樣由于current是樹葉,可以斷定brother的兩個黑色的兒子節(jié)點下面至多只能有一層紅色子節(jié)點,下面根據(jù)brother左兒子的子節(jié)點情況(右兒子的子節(jié)點沒有影響,因此忽略)來分情形討論。

2.1 還是先看brother的左兒子沒有子節(jié)點的情況,這時可以將brother與其左兒子進行換色,然后將parent進行左旋。

2.2 如果brother的左兒子有一個紅色右子節(jié)點,這時需要先將brother左兒子的右子節(jié)點涂成黑色,并將brother右旋,然后再將parent左旋。

 

2.3 如果brother的左兒子沒有紅色右子節(jié)點,但有一個紅色左子節(jié)點。這時可以先將brother左兒子的左子節(jié)點涂成黑色,并將brother的左兒子右旋,這樣將情形轉化成2.2, 然后依次將brother右旋,parent左旋。

 

因此,需要根據(jù)brother左兒子的子節(jié)點情況將情形2再分為3種子情形來處理。

3.parent為黑色,brother為黑色

還是由于current是樹葉,可以斷定brother下面至多只能有一層紅色的兒子節(jié)點,否則parent在刪除前就違反了規(guī)則4。

3.1 還是先看brother沒有兒子的情況,此時通過parent為根的子樹自身已經(jīng)解決不了問題,想法是將brother變成紅色來降低parent子樹的黑高,然后將parent子樹整個視為一個current進行處理, 下面會再詳細說明。

3.2 如果brother有一個紅色右兒子,這時可以將brother的右兒子變成黑色,然后將parent左旋。

 

3.3 如果brother沒有紅色右兒子,但是存在一個紅色左兒子,這時可以將brother的左兒子變成黑色,然后將brother右旋,再將parent左旋。

 

因此,需要根據(jù)brother的子節(jié)點情況將情形3再分為3種子情形來處理。

小結一下,上面一共將刪除了黑色樹葉的情形分成了8種,除了3.1,其它都可以在parent子樹內(nèi)部解決問題。為了進一步分析3.1的問題,需要擴展下思維, 可以想象一下,將current是樹葉這個前提去掉,然后將current視為根為黑色的子樹。假設這時刪除的黑色樹葉落在current子樹下面, 并且遇到了情形3.1,那么可以看成將current子樹整體的黑高降1,然后再根據(jù)brother子樹和parent的情況來進行處理。

如果依然解決不了問題, 那么可以將parent樹視為新的current子樹, 再將祖父節(jié)點視為新的parent,這樣逐層向上分析,直到能夠在新的parent為根的樹內(nèi)部解決問題或者到達樹根為止。

下面通過畫圖再對上面的情形進行一遍說明,對于空節(jié)點nil可以使用黑色節(jié)點代替。另外,這時有一個前提假設:即在刪除之前current子樹的黑高一定大于1, 那么brother子樹的黑高必然也至少為2,也就是說brother到nil的路徑上必然還有黑色節(jié)點。

為了更好的說明,圖中用x標出樹根, 并用a,b,c,d,e,f,g,h標出樹根下面的一些相對位置(可以將這些位置看成nil,只是圖中做了省略,沒有畫出current和brother到這些nil的完整路徑)。所有圖的最終目標的都是保證:如果current子樹的黑高降1,那么通過調(diào)整保證x到a,b,c,d,e,f,g,h這些位置的相對黑高不變。

對于1.1,如果current子樹黑高降1,與之前一樣,直接將parent左旋,可以保證在調(diào)整前后,x到a,b,c,d,e的相對黑高保持不變,如圖:

 

對于1.2,如果current子樹黑高降1,與之前一樣,先將brother右旋,然后將parent變成黑色并左旋,也能保證x到a,b,c,d,e的相對黑高保持不變,如圖:

 

對于2.1,如果current子樹黑高降1,與之前一樣,將brother與左兒子換色,然后對parent左旋,可以保證x到a,b,c,d,e,f,g,h的相對黑高保持不變,如圖:

 

對于2.2,如果current子樹黑高降1,與之前一樣,將brother的左兒子的右子節(jié)點涂成黑色,然后對brother右旋,再對parent左旋,也可以保證x到a,b,c,d,e,f,g,h的相對黑高保持不變, 如圖(A涂成灰色表示其顏色可以紅或者黑,沒有影響):

 

對于2.3,如果current子樹黑高降1,與之前一樣,先將brother的左兒子的左子節(jié)點涂成黑色,并對將brother的左兒子右旋,這樣將情形轉化成2.2,然后再進行同樣的旋轉調(diào)整, 以保證x到a,b,c,d,e,f,g,h的相對黑高保持不變,如圖:

 

對于3.1,如果current子樹黑高降1,與之前一樣,依然只能降低brother的黑高,使x到a,b,c,d,e,f的相對黑高同時降1,然后將parent視為新的current子樹繼續(xù)向樹根追溯,如圖:

 

對于3.2,如果current子樹黑高降1,與之前一樣,將brother的右兒子涂黑,然后對parent左旋,也能保證x到a,b,c,d,e,f的相對黑高保持不變, 如圖(圖中將left涂成灰色表示其顏色可以紅或者黑,沒有影響):

 

對于3.3,如果current子樹黑高降1,與之前一樣,先將brother的左兒子涂黑,然后對parent右旋,再對parent左旋,也能保證x到a,b,c,d,e,f的相對黑高保持不變,如圖:

 

總結節(jié)點刪除問題:首先將問題轉化為對樹葉的刪除,如果樹葉是紅色則直接刪除,如果是黑色,則根據(jù)兄弟節(jié)點和父節(jié)點的顏色情況來對情形進行分類。想法是盡量在子樹中解決, 如果實在解決不了,就降低子樹的高度,并將子樹視為整體然后向樹根進行追溯,直到問題解決。上面的分析中,對于刪除黑色樹葉的刪除,分成了8種情形,其中3.1需要向樹根追溯, 直到轉化成其它7種情形或到樹根為止才能解決。其次,2.3也需要轉化成2.2來解決,因此,對于黑色樹葉的刪除,實際上最后直接解決的情形可以歸結有6種。

3. java實現(xiàn)

繼承之前二叉查找樹的實現(xiàn),重寫下插入和刪除,分別實現(xiàn)Set和MultiTreeMap

3.1. Set

 
 
 
 
  1. public class RBTreeSet> extends BinarySearchTreeSet { 
  2.  
  3.   private RBNode header; 
  4.  
  5.   private RBNode nil; 
  6.  
  7.   public RBTreeSet() { 
  8.     nil = new RBNode<>(null); 
  9.     nil.left = nil; 
  10.     nil.right = nil; 
  11.     header = new RBNode<>(null, nil, nil); 
  12.   } 
  13.  
  14.   @Override 
  15.   protected Node getRoot() { 
  16.     return header.right; 
  17.   } 
  18.  
  19.   @Override 
  20.   protected boolean isEmptyNode(Node node) { 
  21.     return nil == node; 
  22.   } 
  23.    
  24.   @Override 
  25.   public void clear() { 
  26.     header.right = nil; 
  27.     size = 0; 
  28.   } 
  29.  
  30.   @Override 
  31.   public boolean add(E e) { 
  32.     RBNode current = header; 
  33.     RBNode parent = header; 
  34.     //先將nil的值設為e 
  35.     nil.element = e; 
  36.     //然后從header開始自上而下尋找值為e的節(jié)點a 
  37.     while(compare(e, current) != 0){ 
  38.       parent = current; 
  39.       if(compare(e, current) < 0){ 
  40.         current = getLeft(current); 
  41.       }else{ 
  42.         current = getRight(current); 
  43.       } 
  44.       //如果左右子節(jié)點都為紅色,則進行顏色翻轉,避免插入時出現(xiàn)父親的兄弟節(jié)點為紅色的情況 
  45.       if(getLeft(current).red && getRight(current).red){ 
  46.         current = handleReorient(current); 
  47.       } 
  48.     } 
  49.  
  50.     //如果發(fā)現(xiàn)了值相同的重復節(jié)點,直接覆蓋 
  51.     if(current != nil){ 
  52.       current.element = e; 
  53.       return true; 
  54.     } 
  55.  
  56.     //新建一個數(shù)據(jù)節(jié)點代替nil,并將其左右子樹指向nil 
  57.     current = new RBNode<>(e, nil, nil); 
  58.     size++; 
  59.  
  60.     //當while結束時,必然可以明確待插入節(jié)點的parent節(jié)點,這里使parent節(jié)點鏈接到新節(jié)點 
  61.     current.parent = parent; 
  62.     if(compare(e, parent) < 0){ 
  63.       parent.left = current; 
  64.     }else{ 
  65.       parent.right = current; 
  66.     } 
  67.  
  68.     //將新數(shù)據(jù)節(jié)點設成紅色,如果父親節(jié)點為紅色則需要旋轉調(diào)整 
  69.     handleReorient(current); 
  70.     return true; 
  71.   } 
  72.  
  73.   private RBNode getLeft(Node node){ 
  74.     return (RBNode)node.left; 
  75.   } 
  76.  
  77.   private RBNode getRight(Node node){ 
  78.     return (RBNode)node.right; 
  79.   } 
  80.  
  81.   private int compare(E e, Node node) { 
  82.     if(node == header){ 
  83.       return 1; 
  84.     }else{ 
  85.       return e.compareTo(node.element); 
  86.     } 
  87.   } 
  88.  
  89.   private RBNode handleReorient(RBNode current) { 
  90.     getLeft(current).red = false;   
  91.     getRight(current).red = false;  
  92.     current.red = true; 
  93.  
  94.     RBNode subRoot = current; 
  95.     //翻轉之后發(fā)現(xiàn)parent也是紅色,進行換色和旋轉 
  96.     RBNode parent = current.parent; 
  97.     if(parent.red){ 
  98.       RBNode grand = parent.parent; 
  99.       grand.red = true; 
  100.       //旋轉parent, 向外旋轉到同一側  
  101.       if(compare(current.element, grand) != compare(current.element, parent)) { 
  102.         if(compare(current.element, parent) > 0){ 
  103.           rotateLeft(parent); 
  104.         }else{ 
  105.           rotateRight(parent); 
  106.         } 
  107.       } 
  108.       //旋轉grand 
  109.       if(compare(current.element, grand) < 0){ 
  110.         subRoot = getLeft(grand); 
  111.         subRoot.red = false; 
  112.         rotateRight(grand); 
  113.       }else{ 
  114.         subRoot = getRight(grand); 
  115.         subRoot.red = false; 
  116.         rotateLeft(grand); 
  117.       } 
  118.     } 
  119.     //直接將根節(jié)點置為黑色  
  120.     getRight(header).red = false; 
  121.     return subRoot; 
  122.   } 
  123.  
  124.   private void rotateRight(RBNode node) { 
  125.     RBNode parent = node.parent; 
  126.     RBNode left = getLeft(node);  
  127.     RBNode leftRight = getRight(left); 
  128.     left.right = node; 
  129.     node.parent = left; 
  130.     node.left = leftRight; 
  131.     leftRight.parent = node; 
  132.     left.parent = parent; 
  133.     if(parent.right == node){ 
  134.       parent.right = left; 
  135.     }else{ 
  136.       parent.left = left; 
  137.     } 
  138.   } 
  139.  
  140.   private void rotateLeft(RBNode node) { 
  141.     RBNode parent = node.parent; 
  142.     RBNode right = getRight(node);  
  143.     RBNode rightLeft = getLeft(right); 
  144.     right.left = node; 
  145.     node.parent = right; 
  146.     node.right = rightLeft; 
  147.     rightLeft.parent = node; 
  148.     right.parent = parent; 
  149.     if(parent.right == node){ 
  150.       parent.right = right; 
  151.     }else{ 
  152.       parent.left = right; 
  153.     } 
  154.   } 
  155.  
  156.   @Override 
  157.   public boolean remove(Object o) { 
  158.     RBNode current = header; 
  159.     RBNode parent = header; 
  160.      
  161.     @SuppressWarnings("unchecked") 
  162.     E e = (E)o; 
  163.     nil.element = e; 
  164.     while(compare(e, current) != 0){ 
  165.       parent = current; 
  166.       if(compare(e, current) < 0){ 
  167.         current = getLeft(current); 
  168.       }else{ 
  169.         current = getRight(current); 
  170.       } 
  171.     } 
  172.  
  173.     if(current == nil){ //沒有找到值為e的數(shù)據(jù)節(jié)點 
  174.       return true; 
  175.     } 
  176.  
  177.     size--; 
  178.     RBNode node = current; 
  179.     if(current.right != nil){ //替換右子樹最小節(jié)點 
  180.       parent = current; 
  181.       current = getRight(current); 
  182.       while(current.left != nil){ 
  183.         parent = current; 
  184.         current = getLeft(current); 
  185.       } 
  186.       node.element = current.element; 
  187.       //右側最小節(jié)點不是葉子,則繼續(xù)向下遍歷一層,這時可以斷定樹葉是紅色 
  188.       if(current.right != nil){ 
  189.         parent = current; 
  190.         current = getRight(current); 
  191.         parent.element = current.element; 
  192.         parent.right = nil; 
  193.         return true; 
  194.       } 
  195.     }else if(current.left != nil){ //替換左子樹最大節(jié)點 
  196.       parent = current; 
  197.       current = getLeft(node); 
  198.       while(current.right != nil){ 
  199.         parent = current; 
  200.         current = getRight(current); 
  201.       } 
  202.       node.element = current.element; 
  203.       //左側最大節(jié)點不是葉子,則繼續(xù)向下遍歷一層,這時可以斷定樹葉是紅色 
  204.       if(current.left != nil){ 
  205.         parent = current; 
  206.         current = getLeft(current); 
  207.         parent.element = current.element; 
  208.         parent.left = nil; 
  209.         return true; 
  210.       } 
  211.     } 
  212.  
  213.     //先調(diào)整再刪除,因為后面還需要依賴current與parent的位置關系判斷 
  214.     if(!current.red){ 
  215.       fixRemove(current); 
  216.     } 
  217.      
  218.     //刪除樹葉leaf 
  219.     if(current == parent.left){ 
  220.       parent.left = nil; 
  221.     }else{ 
  222.       parent.right = nil; 
  223.     } 
  224.     return true; 
  225.   } 
  226.  
  227.   private void fixRemove(RBNode current){ 
  228.     RBNode parent = current.parent; 
  229.     if(parent == header){ 
  230.       return; 
  231.     } 
  232.  
  233.     if(current == parent.left){ 
  234.       RBNode brother = getRight(parent); 
  235.       if(parent.red){ // 1.parent為紅色 
  236.         if(getLeft(brother).red){  
  237.           parent.red = false; 
  238.           rotateRight(brother); 
  239.         } 
  240.       }else if(brother.red){ // 2.brother為紅色 
  241.         if(!getLeft(brother.left).red && !getRight(brother.left).red){ 
  242.           brother.red = false; 
  243.           getLeft(brother).red = true; 
  244.         }else if(getRight(brother.left).red){ 
  245.           getRight(brother.left).red = false; 
  246.           rotateRight(brother); 
  247.         }else{ 
  248.           getLeft(brother.left).red = false; 
  249.           rotateRight(getLeft(brother)); 
  250.           rotateRight(brother); 
  251.         } 
  252.       }else{ // 3. parent和brother都為黑色 
  253.         if(!getLeft(brother).red && !getRight(brother).red){  
  254.           brother.red = true; 
  255.           fixRemove(parent); 
  256.           return; 
  257.         }else if(getRight(brother).red){ 
  258.           getRight(brother).red = false; 
  259.         }else{ 
  260.           getLeft(brother).red = false; 
  261.           rotateRight(brother); 
  262.         } 
  263.       } 
  264.       //最后一步的調(diào)整都是parent左旋 
  265.       rotateLeft(parent); 
  266.     }else{ // 對稱情形 
  267.       RBNode brother = getLeft(parent);    
  268.       if(parent.red){  
  269.         if(getRight(brother).red){  
  270.           parent.red = false; 
  271.           rotateLeft(brother); 
  272.         } 
  273.       }else if(brother.red){     
  274.         if(!getLeft(brother.right).red && !getRight(brother.right).red){ 
  275.           brother.red = false; 
  276.           getRight(brother).red = true; 
  277.         }else if(getLeft(brother.right).red){ 
  278.           getLeft(brother.right).red = false; 
  279.           rotateLeft(brother); 
  280.         }else{ 
  281.           getRight(brother.right).red = false; 
  282.           rotateLeft(getRight(brother)); 
  283.           rotateLeft(brother); 
  284.         } 
  285.       }else{  
  286.         if(!getLeft(brother).red && !getRight(brother).red){ 
  287.           brother.red = true; 
  288.           fixRemove(parent); 
  289.           return; 
  290.         }else if(getLeft(brother).red){ 
  291.           getLeft(brother).red = false; 
  292.         }else{ 
  293.           getRight(brother).red = false; 
  294.           rotateLeft(brother); 
  295.         } 
  296.       } 
  297.       rotateRight(parent); 
  298.     } 
  299.   } 
  300.  
  301.   static class RBNode extends Node { 
  302.  
  303.     RBNode parent; 
  304.  
  305.     boolean red; 
  306.  
  307.     RBNode(E e) { 
  308.       super(e); 
  309.     } 
  310.  
  311.     RBNode(E e, RBNode left, RBNode right) { 
  312.       super(e); 
  313.       this.left = left; 
  314.       this.right = right; 
  315.     } 
  316.  
  317.     @Override 
  318.     public String toString() { 
  319.       return red ? element.toString() + "(red)" : element.toString(); 
  320.     } 
  321.   } 

3.2. MultiTreeMap

 
 
 
 
  1. public class MultiRBTreeMap, V> extends MultiBinarySearchTreeMap { 
  2.  
  3. public MultiRBTreeMap() { 
  4.  
  5.   } 
  6.  
  7. public MultiRBTreeMap(boolean deduplication, boolean asc){ 
  8. super(deduplication, asc); 
  9.   } 
  10.  
  11.   @Override 
  12.   protected void init() { 
  13. nil = new RBNode(null, null, false, null, null); 
  14. nil.left = nil; 
  15. nil.right = nil; 
  16.     header = new RBNode(null, null, false, nil, nil); 
  17.     header.next = nil; 
  18. nil.prev = header; 
  19.   } 
  20.  
  21. public V put(K key, V value){ 
  22. nil.key = key; 
  23. RBNode current = (RBNode)header; 
  24. RBNode parent = (RBNode)header;  
  25. while(compare(key, current) != 0){ 
  26.       parent = current; 
  27. if(compare(key, current) < 0){ 
  28.         current = getLeft(current); 
  29.       }else{ 
  30.         current = getRight(current); 
  31.       } 
  32. if(getLeft(current).isRed && getRight(current).isRed){ 
  33.         current = handleReorient(current); 
  34.       } 
  35.     } 
  36.  
  37. if(current != nil){ 
  38. if(deduplication){ 
  39. V old = current.value; 
  40.         current.key = key; 
  41.         current.value = value; 
  42. return old; 
  43.       }else{ 
  44. while((current = getNext(current)).isRepeat);  
  45. V old = current.prev.value; 
  46.         linkIn(new RBNode<>(key, value, true, nil, nil), current, false); 
  47. return old; 
  48.       } 
  49.     } 
  50.  
  51.     current = new RBNode<>(key, value, false, nil, nil); 
  52.     current.parent = parent; 
  53. if(compare(key, parent) < 0){ 
  54.       parent.left = current; 
  55.       linkIn(current, parent, false); 
  56.     }else{ 
  57.       parent.right = current; 
  58. while((parent = getNext(parent)).isRepeat); 
  59.       linkIn(current, parent, false); 
  60.     } 
  61. //將新數(shù)據(jù)節(jié)點設成紅色,如果父親節(jié)點為紅色則需要旋轉調(diào)整 
  62.     handleReorient(current); 
  63. return null; 
  64.   } 
  65.  
  66. private RBNode handleReorient(RBNode current) { 
  67.     getLeft(current).isRed = false;   
  68.     getRight(current).isRed = false;  
  69.     current.isRed = true; 
  70.  
  71. RBNode subRoot = current;  
  72. RBNode parent = getParent(current); 
  73. if(parent.isRed){ 
  74. RBNode grand = getParent(parent); 
  75.       grand.isRed = true; 
  76. //旋轉parent, 向外旋轉到同一側  
  77. if(compare(current.getKey(), grand) != compare(current.getKey(), parent)) { 
  78. if(compare(current.getKey(), parent) > 0){ 
  79.           rotateLeft(parent); 
  80.         }else{ 
  81.           rotateRight(parent); 
  82.         } 
  83.       } 
  84. //旋轉grand 
  85. if(compare(current.getKey(), grand) < 0){ 
  86.         subRoot = getLeft(grand); 
  87.         subRoot.isRed = false; 
  88.         rotateRight(grand); 
  89.  &nb
    分享標題:他一口氣寫出了這7k字的紅黑樹總結!看過的都說好?。?
    標題來源:http://www.dlmjj.cn/article/djdsoih.html