深刻理解紅黑樹

  紅黑樹是平衡樹的一種,保證最壞狀況下操做時間複雜度爲O(lgo(n))。紅黑樹的應用比較普遍,好比做爲C++中STL的set和map的底層數據結構,Java集合中TreeSet和TreeMap的底層數據結構等。學習紅黑樹,能夠把二叉查找樹做爲參考,這樣有助於加深理解。紅黑樹的操做主要包括節點旋轉、插入、刪除等操做,下面我們就一一來看:java

一、紅黑樹性質

  1. 每一個節點是紅色的,或者是黑色的
  2. 根節點是黑色的
  3. 每一個葉節點(nil)是黑色的
  4. 若是一個節點是紅色的,則它的兩個子節點都是黑色的
  5. 對每一個節點,從該節點到其後代葉節點的簡單路徑上,均包含相同數目的黑色節點

紅黑樹總體節點圖示以下:node

二、旋轉

  旋轉是保持二叉搜索樹(紅黑樹)局部性質的操做,包括左旋和右旋。當在節點x上作左旋時,假設它的右孩子爲y而不是T.nil,X可爲其右孩子不是T.nil的任何節點,同理,X作右旋也是同樣的。git

僞代碼以下(左旋)github

左旋Java示例代碼:算法

/** * 左旋操做 */ private void leftRotate(Node x) { Node y = x.right; x.right = y.left; if (y.left != nil) { y.left.parent = x; } y.parent = x.parent; if (x.parent == nil) { root = y; } else if (x == x.parent.left) { x.parent.left = y; } else { x.parent.right = y; } x.parent = y; y.left = x; }

三、插入

  在O(log(n))時間內插入一個節點,RB-INSERT過程完成該操做,像一個普通的二叉搜索樹插入操做同樣,而後將要插入的節點Z着爲紅色。爲了保持紅黑樹的性質,調用一個輔助函數RB-INSERT-FIXUP來對節點從新着色並旋轉。待插入節點Z已保存了數據項。數據結構

RB-INSERT-FIXUP過程僞代碼app


  注意:Case1屬於if判斷條件,Case2和Case3屬於else語句,Case2是else語句中的if判斷語句的。具體能夠看代碼。ide

插入過程Java代碼示例:函數

/** * 往紅黑樹中插入一個元素 * @param data */ public void insert(int data) { Node y = nil; Node x = root; if (root == nil) { root = newNode(data); root.color = Node.BLACK; } else { while (x != nil) { if (data < x.data) { y = x; x = x.left; } else if (data > x.data) { y = x; x = x.right; } else { return; } } Node z = newNode(data); z.parent = y; if (data < y.data) { y.left = z; } else { y.right = z; } if (y.color == Node.RED) { insertFixup(z); } } }

RB-INSERT-FIXUP過程分析學習

  第1-15行的while循環在每次迭代的開始始終保持如下3個條件是不變的

  1. 節點z是紅節點
  2. 若是z.p是根節點,則z.p是黑節點
  3. 若是有任何紅黑樹性質貝破壞,則至多有一條被破壞,或是性質2,或是性質4(各個性質見紅黑樹性質總結)。若是性質2被破壞,則由於z是根節點且是紅節點。性質4被破壞則是由於z和z.p都是紅節點。

循環終止條件:

  循環終止由於z.p是黑色的(若是z是根節點,則z.p是黑色哨兵節點),這樣,在循環終止時並無違反性質4,惟一可能不成立的就是性質2,不過第16行(僞代碼中的行)恢復了這個性質。

循環保持條件:

  循環保持有6中條件,其中3種和另外3種是對稱的,這取決於z的父節點z.p是z的祖父節點z.p.p的左孩子仍是右孩子。狀況一、二、3的區別就在於z 的父節點的兄弟節點(z的叔節點)的顏色不一樣,加入y指向z的叔節點,若是y的顏色是紅色的,則執行狀況1,不然轉向狀況2和3。在全部的3種狀況中,z 的祖父節點z.p.p是黑色的,由於他的父節點z.p是紅色的,故性質4只有在z和z.p之間被破壞了。

 

狀況1:z的叔節點y是紅色的

       此時對應Case1,將z.p和y都着成黑色,解決z和z.p都是紅色的問題,將z.p.p着成紅色保持性質5,而後把z.p.p做爲新節點z來繼續進行while循環,指針z上移兩層

狀況2:z的叔節點y是黑色的且z是一個右孩子

狀況3:z的叔節點y是黑色的且z是一個左孩子

       兩種狀況中,y都是黑色的,經過z是左孩子仍是右孩子來區分,狀況2中能夠經過一個左旋來轉化爲狀況3,此時z爲左孩子。由於z和z.p都是紅節點,對黑 高(從某個節點出發,不含該節點,到達一個葉節點的任意一條簡答路徑上的黑色節點數爲該節點的黑高)和性質5都無影響。在狀況3中,改變某些節點顏色並作 一次右旋,保持性質5,這樣不在有兩個紅色節點相鄰,處理完畢,此時z.p是黑色的,因此無需再執行while循環了。

RB-INSERT-FIXUP的Java代碼實現

/**
 * 插入節點後不知足紅黑樹條件時來修復
 * @param z 待插入的節點
 */
private void insertFixup(Node z) {
    // y爲z節點的叔叔節點
    Node y = null;
    
    while (z.parent.color == Node.RED) {
        if (z.parent == z.parent.parent.left) {
            y = z.parent.parent.right;
            if (y.color == Node.RED) {
                z.parent.color = Node.BLACK;
                y.color = Node.BLACK;
                z.parent.parent.color = Node.RED;
                z = z.parent.parent;
            } else {
                if (z == z.parent.right) {
                    z = z.parent;
                    leftRotate(z);
                }
                
                z.parent.color = Node.BLACK;
                z.parent.parent.color = Node.RED;
                rightRotate(z.parent.parent);
            }
        } else {
            y = z.parent.parent.left;
            if (y.color == Node.RED) {
                z.parent.color = Node.BLACK;
                y.color = Node.BLACK;
                z.parent.parent.color = Node.RED;
                z = z.parent.parent;
            } else {
                if (z == z.parent.left) {
                    z = z.parent;
                    rightRotate(z);
                }
                
                z.parent.color = Node.BLACK;
                z.parent.parent.color = Node.RED;
                leftRotate(z.parent.parent);
            }
        }
    }
    
    root.color = Node.BLACK;
}

四、刪除

  刪除操做與插入操做相比,略顯複雜,與插入操做同樣,也要花費O(log(n))時間。從紅黑樹中刪除節點,需設計一個供TREE-DELETE調用的子過程TRANSPLANT,並應用到紅黑樹中,TRANSPLANT過程用來調整兩個節點的關係,其中的一個節點要替換掉另外一個節點

TRANSPLANT過程

  u節點表示將要被替換掉的節點,v節點是準備替換u節點的

RB-TRANSPLANT的Java代碼實現

/**
 * 兩個節點的替換,newNode替換oldNode
 * @param oldNode
 * @param newNode
 */
private void transplant(Node oldNode, Node newNode) {
    if (oldNode.parent == nil) {
        root = newNode;
    } else if (oldNode == oldNode.parent.left) {
        oldNode.parent.left = newNode;
    } else {
        oldNode.parent.right = newNode;
    }
    
    newNode.parent = oldNode.parent;
}

RB-DELETE過程

  RB-DELETE中,z節點是要被刪除的節點,其中記錄了節點y的蹤影,y有可能致使紅黑樹性質破壞,當想刪除節點z,且z的子節點少於2個時,z從書中刪除,並讓y稱爲z。當z有兩個子節點時,y應該是z的後繼,而且將y移到z的位置。在節點被刪除或者移動時,必須記住y的顏色,而且記錄節點x的蹤影,將x移到y的原來的位置,由於節點x可能引發紅黑樹性質破壞。刪除節點z後,RB-DELETE-FIXUP過程經過改變顏色和執行旋轉來恢復紅黑樹性質。

  咱們保存節點x的蹤影,使它移至節點y的原來位置。第四、7和11行的賦值語句令x或指向y的惟一子節點或指向y哨兵T.nil(y沒有子節點的話)。  第五、8或14行調用RB-TRANSPLANT時,傳遞的第2個參數與x相同

  若是y是黑色的,則有可能引入一個或多個破壞紅黑色的狀況,因此在第22行調用RB-TRANSPLANT來恢復紅黑樹性質。若是y是紅色的,當y被刪除或移動時,紅黑樹性質依然成立,由於(1) 樹中黑高沒有變化 (2) 不存在兩個相鄰的紅節點,由於y在樹中佔據了z的位置,z的位置確定不會違反紅黑樹性質的。另外,若是y是z的右孩子,則y的原右孩子x代替y,若是y是紅色的,則x必定是黑色的,一次用x替代y不會使兩個紅節點相鄰。 (3) 若是y是紅色的,就不會是根節點,因此根節點仍然是黑色的。

y爲黑節點狀況分析

RB-DELETE的Java代碼實現

/**
 * 從紅黑樹中移除一個元素
 * @param data 待移除的元素
 */
public void remove(int data) {
    Node z = contains(data);
    if (z == null) {
        return;
    }
    
    Node x;
    Node y = z;
    int yOldColor = y.color;
    if (z.left == nil) {
        x = z.right;
        transplant(z, x);
    } else if (z.right == nil) {
        x = z.left;
        transplant(z,  x);
    } else {
        y = z.right;
        while (y.left != nil) {
            y = y.left;
        }
        yOldColor = y.color;
        x = y.right;
        
        if (y.parent == z) {
            x.parent = y;
        } else {
            transplant(y, y.right);
            y.right = z.right;
            y.right.right = y;
        }
        
        transplant(z, y);
        y.left = z.left;
        y.left.parent = y;
        y.color = z.color;
    }
    
    if (yOldColor == Node.BLACK) {
        removeFixup(x);
    }
}

RB-DELETE-FIXUP過程

ps:圖片上的狀況層次關係對應不是很齊,能夠看碼來的清楚

4種狀況的轉換關係

  • 1 -> 二、三、4
  • 2 -> 一、二、三、四、修復 (只有Case2是節點上移,全部有可能會使x=root)
  • 3 -> 4
  • 4 -> 修復

  不管哪一個Case,要麼是爲了到達平衡兩個節點,路徑上黑色數目相同的目的,要麼是經過變形間接達到這個目的。

while循環的目標是將額外的黑色沿樹上移,直到:

  1. x指向紅黑節點,此時在第23行處將x着爲(單個)黑色
  2. x指向根節點,此時能夠簡單地移除額外的黑色
  3. 執行適當的旋轉和從新着色

代碼中的4種狀況圖示


       上圖給出了代碼中出現的四種狀況,再具體研究每個狀況時,先看看如何證明每種狀況中的變換保證性質5。關鍵思想是在每種狀況下,從子樹的跟(包括跟)到每棵子樹之間的黑色節點個數(包括x的額外黑色)並不被變換改變,所以,若是性質5在變換以前成立,則在變換以後也成立。好比:在狀況1中,在變換先後,根節點到子樹a或b之間的黑色節點數是3(由於x增長了一層黑色),相似的,在變換先後根節點到其他的4個子樹的葉節點中的任何一個的黑節點數是2。在圖13-7(b)中,計數是還要包括所示子樹的根節點的color屬性的值,它是RED或是BLACK,若是定義count(RED)=0以及count(BLACK)=1,那麼變換先後根節點至a的黑節點都爲2+count(c)。在此狀況下,變換以後新節點x具備color屬性的c,可是這個節點的顏色是紅黑(若是c=RED)或者雙重黑色的(若是c=BLACK)。其餘狀況能夠相似加以驗證。

狀況1:x的兄弟節點w是紅色的

  狀況1(見RB-DELETE-FIXUP的第5-8行和圖13-7(a))發生在節點x的兄弟節點w爲紅色時。由於w必須有黑色子節點,全部能夠改變w的x.p的顏色,而後對x.p作一次左旋而不違反紅黑樹的任何性質。如今x的新兄弟節點是旋轉以前w的某個子節點,其顏色爲黑色。這樣,就將狀況1轉變爲了狀況二、3或者4。

  當節點w爲黑色時,屬於狀況二、3或者4;這些狀況有w的子節點顏色來區分了。

狀況2:x的兄弟節點w是黑色的,並且w的兩個子節點都是黑色的

  在狀況2(見RB-DELETE-FIXUP的第10-11行和圖13-7(b)),w的兩個子節點都是黑色的,由於w也是黑色的,因此從x和w上去掉一重黑色,使得x只有一重黑色而w爲紅色。爲了補償從x和w中去掉的一重黑色,在原來是紅色或黑色的x.p上增長一重額外的黑色。經過將x.p做爲新節點x來重複while循環。注意到,若是經過狀況1進入到狀況2,則新節點x就是紅黑色的,由於原來的x.p是紅色的,所以,新節點x的color屬性值爲RED,而且在測試循環條件後循環終止。而後,在第23行處將新節點x着爲(單一)黑色。

狀況3:x的兄弟節點w是黑色的,w的左孩子是紅色的,w的右孩子是黑色的

  狀況3(見RB-DELETE-FIXUP的第13-16行和圖13-7(c))發生在w爲黑色且其左孩子爲紅色,右孩子爲黑色時。能夠交換w和其左孩子w.left的顏色,而後對w進行右旋而不違反紅黑樹的性質。如今x的新節點w是一個有紅色右孩子的黑色節點,這樣咱們就從狀況3轉換成了狀況4。

狀況4:x的兄弟節點w是黑色的,且w的右孩子是紅色的

  狀況4(見RB-DELETE-FIXUP的第17-21行和圖13-7(d))發生在節點x的兄弟節點w爲黑色且w的右孩子爲紅色時,經過進行某些顏色修改並對x.p作一次左旋,能夠去掉x的額外黑色,從而使它變爲單重黑色,並且不破壞紅黑樹性質。將x設爲設爲根root後,當while循環測試其循環條件時,循環終止。

RB-DELETE-FIXUP的Java代碼實現

/**
 * 移除一個元素後紅黑樹不符合要求時的修復方法
 * @param x
 */
private void removeFixup(Node x) {
    Node y;
    
    while (x != root && x.color == Node.BLACK) {
        if (x == x.parent.left) {
            y = x.parent.right;
            if (y.color == Node.RED) { //狀況1:x的兄弟節點w是紅色
                y.color = Node.BLACK;
                x.parent.color = Node.RED;
                leftRotate(x.parent);
                y = x.parent.right;
            }
            
            if (y.left.color == Node.BLACK && y.right.color == Node.BLACK) { //狀況2:x的兄弟節點w是黑色,並且w的兩個子節點都是黑色的
                y.color = Node.RED;
                x = x.parent;
            } else {
                if (y.right.color == Node.BLACK) { //狀況3:x的兄弟節點w是黑色的,w的左孩子是紅色的,w的右孩子是黑色的
                    y.left.color = Node.BLACK;
                    y.color = Node.RED;
                    rightRotate(y);
                    y = x.parent.right;
                }
                
                y.color = x.parent.color; //狀況4:x的兄弟節點w是黑色的,且w的右孩子是紅色的
                x.parent.color = Node.BLACK;
                y.right.color = Node.BLACK;
                leftRotate(x.parent);
                x = root;
            }
        } else {
            y = x.parent.left;
            if (y.color == Node.RED) {
                y.color = Node.BLACK;
                x.parent.color = Node.RED;
                rightRotate(x.parent);
                y = x.parent.left;
            }
            
            if (y.left.color == Node.BLACK && y.right.color == Node.BLACK) {
                y.color = Node.RED;
                x = x.parent;
            } else {
                if (y.left.color == Node.BLACK) {
                    y.right.color = Node.BLACK;
                    y.color = Node.RED;
                    leftRotate(y);
                    y = x.parent.left;
                }
                
                y.color = x.parent.color;
                x.parent.color = Node.BLACK;
                y.left.color = Node.BLACK;
                rightRotate(x.parent);
                x = root;
            }
        }
    }
    x.color = Node.BLACK;
}

刪除分析:

五、完整程序Java代碼實現

紅黑樹Rbtre.java文件:

  1 package tree;
  2 
  3 /**
  4  * 紅黑樹節點類
  5  */
  6 class Node {
  7     // 紅黑節點顏色
  8     public final static int RED = 0;
  9     public final static int BLACK = 1;
 10     
 11     // ------------------------------ Instance Variables
 12     
 13     public Node left;    // 左節點
 14     public Node right;    // 右節點
 15     public Node parent; // 父節點
 16     public int color;    // 節點顏色
 17     public int data;    // 數據域,int型數據
 18 }
 19 
 20 /**
 21  * 紅黑樹類
 22  * 
 23  */
 24 public class Rbtree {
 25     
 26     // ------------------------------ Instance Variables
 27     
 28     // 紅黑樹空節點
 29     public Node nil;
 30     
 31     // 紅黑樹根節點
 32     public Node root;
 33 
 34     // ------------------------------ Constructors
 35     
 36     /**
 37      * Init nil node and root node.
 38      */
 39     public Rbtree() {
 40         nil = new Node();
 41         nil.left = nil.right = nil.parent = nil;
 42         nil.color = Node.BLACK;
 43         root = nil;
 44     }
 45     
 46     // ------------------------------ Public methods
 47     
 48     /**
 49      * 往紅黑樹中插入一個元素
 50      * @param data
 51      */
 52     public void insert(int data) {
 53         Node y = nil;
 54         Node x = root;
 55         
 56         if (root == nil) {
 57             root = newNode(data);
 58             root.color = Node.BLACK;
 59         } else {
 60             while (x != nil) {
 61                 if (data < x.data) {
 62                     y = x;
 63                     x = x.left;
 64                 } else if (data > x.data) {
 65                     y = x;
 66                     x = x.right;
 67                 } else {
 68                     return;
 69                 }
 70             }
 71             
 72             Node z = newNode(data);
 73             z.parent = y;
 74             if (data < y.data) {
 75                 y.left = z;
 76             } else {
 77                 y.right = z;
 78             }
 79             if (y.color == Node.RED) {
 80                 insertFixup(z);
 81             }
 82         }
 83     }
 84     
 85     /**
 86      * 從紅黑樹中移除一個元素
 87      * @param data 待移除的元素
 88      */
 89     public void remove(int data) {
 90         Node z = contains(data);
 91         if (z == null) {
 92             return;
 93         }
 94         
 95         Node x;
 96         Node y = z;
 97         int yOldColor = y.color;
 98         if (z.left == nil) {
 99             x = z.right;
100             transplant(z, x);
101         } else if (z.right == nil) {
102             x = z.left;
103             transplant(z,  x);
104         } else {
105             y = z.right;
106             while (y.left != nil) {
107                 y = y.left;
108             }
109             yOldColor = y.color;
110             x = y.right;
111             
112             if (y.parent == z) {
113                 x.parent = y;
114             } else {
115                 transplant(y, y.right);
116                 y.right = z.right;
117                 y.right.right = y;
118             }
119             
120             transplant(z, y);
121             y.left = z.left;
122             y.left.parent = y;
123             y.color = z.color;
124         }
125         
126         if (yOldColor == Node.BLACK) {
127             removeFixup(x);
128         }
129     }
130     
131     /**
132      * 紅黑樹中是否包含data
133      * @param data
134      * @return
135      */
136     public Node contains(int data) {
137         Node node = root;
138         
139         while (node != null) {
140             if (data < node.data) {
141                 node = node.left;
142             } else if (data > node.data) {
143                 node = node.right;
144             } else {
145                 return node;
146             }
147         }
148         return null;
149     }
150     
151     @Override
152     public String toString() {
153         StringBuilder buf = new StringBuilder();
154         
155         if (root != nil) {
156             toStringInternal(root, buf);
157         }
158         return buf.toString();
159     }
160     
161     // ------------------------------ Private methods
162     
163     /**
164      * New a initialize node, default node's color is RED
165      */
166     private Node newNode(int data) {
167         Node node = new Node();
168         
169         node.data = data;
170         node.color = Node.RED;
171         node.left = node.right = node.parent = nil;
172         return node;
173     }
174     
175     private void toStringInternal(Node node, StringBuilder buf) {
176         if (node != nil) {
177             toStringInternal(node.left, buf);
178             buf.append(node.data + (node.color == Node.RED ? "-red " : "-black "));
179             toStringInternal(node.right, buf);
180         }
181     }
182     
183     /**
184      * 兩個節點的替換,newNode替換oldNode
185      * @param oldNode
186      * @param newNode
187      */
188     private void transplant(Node oldNode, Node newNode) {
189         if (oldNode.parent == nil) {
190             root = newNode;
191         } else if (oldNode == oldNode.parent.left) {
192             oldNode.parent.left = newNode;
193         } else {
194             oldNode.parent.right = newNode;
195         }
196         
197         newNode.parent = oldNode.parent;
198     }
199     
200     /**
201      * 左旋操做
202      */
203     private void leftRotate(Node x) {
204         Node y = x.right;
205 
206         x.right = y.left;
207         if (y.left != nil) {
208             y.left.parent = x;
209         }
210         y.parent = x.parent;
211         if (x.parent == nil) {
212             root = y;
213         } else if (x == x.parent.left) {
214             x.parent.left = y;
215         } else {
216             x.parent.right = y;
217         }
218         
219         x.parent = y;
220         y.left = x;
221     }
222     
223     /**
224      * 右旋操做
225      */
226     private void rightRotate(Node x) {
227         Node y = x.left;
228         
229         x.left = y.right;
230         if (y.right != nil) {
231             y.right.parent = x;
232         }
233         y.parent = x.parent;
234         if (x.parent == nil) {
235             root = y;
236         } else if (x == x.parent.left) {
237             x.parent.left = y;
238         } else {
239             x.parent.right = y;
240         }
241         
242         x.parent = y.parent;
243         y.right = x;
244     }
245     
246     /**
247      * 插入節點後不知足紅黑樹條件時來修復
248      * @param z 待插入的節點
249      */
250     private void insertFixup(Node z) {
251         // y爲z節點的叔叔節點
252         Node y = null;
253         
254         while (z.parent.color == Node.RED) {
255             if (z.parent == z.parent.parent.left) {
256                 y = z.parent.parent.right;
257                 if (y.color == Node.RED) { // Case1: x uncle node y is red
258                     z.parent.color = Node.BLACK;
259                     y.color = Node.BLACK;
260                     z.parent.parent.color = Node.RED;
261                 } else {
262                     if (z == z.parent.right) { // Case2: x uncle node y is black, but x is right node
263                         z = z.parent;
264                         leftRotate(z);
265                     }
266                     
267                     z.parent.color = Node.BLACK; // Case3: x uncle node y is black, but x is left node
268                     z.parent.parent.color = Node.RED;
269                     rightRotate(z.parent.parent);
270                 }
271             } else {
272                 y = z.parent.parent.left;
273                 if (y.color == Node.RED) {
274                     z.parent.color = Node.BLACK;
275                     y.color = Node.BLACK;
276                     z.parent.parent.color = Node.RED;
277                 } else {
278                     if (z == z.parent.left) {
279                         z = z.parent;
280                         rightRotate(z);
281                     }
282                     
283                     z.parent.color = Node.BLACK;
284                     z.parent.parent.color = Node.RED;
285                     leftRotate(z.parent.parent);
286                 }
287             }
288         }
289         
290         root.color = Node.BLACK;
291     }
292     
293     /**
294      * 移除一個元素後紅黑樹不符合要求時的修復方法
295      * @param x
296      */
297     private void removeFixup(Node x) {
298         Node y;
299         
300         while (x != root && x.color == Node.BLACK) {
301             if (x == x.parent.left) {
302                 y = x.parent.right;
303                 if (y.color == Node.RED) { //狀況1:x的兄弟節點w是紅色
304                     y.color = Node.BLACK;
305                     x.parent.color = Node.RED;
306                     leftRotate(x.parent);
307                     y = x.parent.right;
308                 }
309                 
310                 if (y.left.color == Node.BLACK && y.right.color == Node.BLACK) { //狀況2:x的兄弟節點w是黑色,並且w的兩個子節點都是黑色的
311                     y.color = Node.RED;
312                     x = x.parent;
313                 } else {
314                     if (y.right.color == Node.BLACK) { //狀況3:x的兄弟節點w是黑色的,w的左孩子是紅色的,w的右孩子是黑色的
315                         y.left.color = Node.BLACK;
316                         y.color = Node.RED;
317                         rightRotate(y);
318                         y = x.parent.right;
319                     }
320                     
321                     y.color = x.parent.color; //狀況4:x的兄弟節點w是黑色的,且w的右孩子是紅色的
322                     x.parent.color = Node.BLACK;
323                     y.right.color = Node.BLACK;
324                     leftRotate(x.parent);
325                     x = root;
326                 }
327             } else {
328                 y = x.parent.left;
329                 if (y.color == Node.RED) {
330                     y.color = Node.BLACK;
331                     x.parent.color = Node.RED;
332                     rightRotate(x.parent);
333                     y = x.parent.left;
334                 }
335                 
336                 if (y.left.color == Node.BLACK && y.right.color == Node.BLACK) {
337                     y.color = Node.RED;
338                     x = x.parent;
339                 } else {
340                     if (y.left.color == Node.BLACK) {
341                         y.right.color = Node.BLACK;
342                         y.color = Node.RED;
343                         leftRotate(y);
344                         y = x.parent.left;
345                     }
346                     
347                     y.color = x.parent.color;
348                     x.parent.color = Node.BLACK;
349                     y.left.color = Node.BLACK;
350                     rightRotate(x.parent);
351                     x = root;
352                 }
353             }
354         }
355         x.color = Node.BLACK;
356     }
357 }
View Code

測試用例程序Main.java文件

 1 package tree;
 2 
 3 public class Main {
 4     public static void main(String[] args) {
 5         Rbtree tree = new Rbtree();
 6         
 7         tree.insert(12);
 8         tree.insert(12);
 9         tree.insert(2);
10         tree.insert(23);
11         tree.insert(1);
12         
13         System.out.println(tree);
14         
15         tree.remove(1);
16         tree.remove(2);
17         tree.remove(12);
18         tree.remove(12);
19         tree.remove(23);
20         System.out.println(tree);
21     }
22 }
View Code

 

參考資料:

  1、《算法導論》第13章 紅黑樹

  二、紅黑樹理解 - 數據結構

  三、更多數據結構實現代碼(C++版)

相關文章
相關標籤/搜索