常見的查找算法(五):樹表查找之二 ---- 紅黑樹


紅黑樹是每個節點都帶有顏色屬性的二叉查找樹,顏色為 紅色 或 黑色。在二叉查找樹強制一般要求以外,對於任何有效的紅黑樹我們增加了如下的額外要求:

  1. 節點是紅色黑色
  2. 黑色
  3. 所有葉子都是黑色(葉子是NIL節點)。
  4. 每個紅色節點必須有兩個黑色子節點。(從每個葉子的所有路徑上不能有兩個連續的紅色節點。)
  5. 任一節點其每個葉子的所有簡單路徑都包含相同數目的黑色節點。

下面是一個具體的紅黑樹的圖例:

旋轉 

 旋轉是一種能保持二叉搜索樹性質的搜索樹局部操作。其中兩種旋轉分別為左旋右旋

 在某個結點 x 上進行左旋時,假設它的右孩子為y而不是樹的 T.nil 結點;x為其右孩子而不是 T.nil 結點的樹內任意節點。

 左旋以 x 到 y 的鏈為“支軸”進行,使得 y 成為該子樹的新的根節點,x 成為 y 的左孩子,y 的左孩子變成 x 的右孩子;右旋與此相反。

左旋代碼:

 1     /**
 2      * 左旋
 3      * 左旋示意圖(對節點x進行左旋):
 4      *     px                               px
 5      *     /                                /
 6      *     x                                y
 7      *    / \          --(左旋)-->         /  \
 8      *   lx   y                           x   ry
 9      *    / \                           /  \
10      *  ly  ry                        lx   ly
11      *
12      * @param x
13      */
14     private void leftRotate(RBTNode<T> x) {
15         RBTNode<T> y = x.right; // y是x的右節點
16 
17         x.right = y.left;       // 把x的左節點變為y的右節點
18         // 若y有左子節點,把y的左節點的父節點換成x
19         if (y.left != null) {
20             y.left.parent = x;
21         }
22 
23         y.parent = x.parent;    // y的父節點(原來是x)設為x的父節點
24 
25         // 若x是根節點,y直接變根節點
26         if (x.parent == null) {
27             this.mRoot = y;
28         } else {
29             if (x.parent.left == x) {
30                 x.parent.left = y;  // 如果x是x父節點的左孩子,把x的父節點的左孩子指向y
31             } else {
32                 x.parent.right = y; // 如果x是x父節點的右孩子,把x的父節點的右孩子指向y
33             }
34         }
35 
36         y.left = x;     // 將y的左節點指向x
37         x.parent = y;   // 將x的父節點設為y
38     }

右旋代碼:

 1     /**
 2      * 右旋,操作和左旋相反
 3      * 右旋示意圖(對節點y進行左旋):
 4      *      py                              py
 5      *     /                                /
 6      *     y                                x
 7      *    / \          --(右旋)-->         /  \
 8      *   x  ry                           lx   y
 9      *   / \                                  / \
10      *  lx  rx                               rx  ry
11      *
12      * @param y
13      */
14     private void rightRotate(RBTNode<T> y) {
15         RBTNode<T> x = y.left;  // y的左孩子
16 
17         y.left = x.right;
18         if (x.right != null) {
19             x.right.parent = y;
20         }
21 
22         x.parent = y.parent;
23 
24         if (y.parent == null) {
25             this.mRoot = x;
26         } else {
27             if (y.parent.left == y) {
28                 y.parent.left = x;
29             } else {
30                 y.parent.right = x;
31             }
32         }
33 
34         x.right = y;
35         y.parent = x;
36     }

紅黑樹新結點插入代碼:

就像一個普通的二叉搜索樹一樣,將新結點插入樹中,並將其着為紅色。之后為了能保證紅黑的性質,還需要一個輔助代碼對結點重新着色並且旋轉。

 1     /**
 2      * 插入操作
 3      *
 4      * @param node
 5      */
 6     private void insert(RBTNode<T> node) {
 7         int result;
 8         RBTNode<T> y = null;
 9         RBTNode<T> x = this.mRoot;
10 
11         // 查找樹中插入點的父結點y的位置
12         while (x != null) {
13             y = x;  // 注意這里,y不是空的
14             result = node.key.compareTo(x.key);
15             if (result < 0) {
16                 x = x.left;
17             } else {
18                 x = x.right;
19             }
20         }
21 
22         node.parent = y;
23         if (y != null) {
24             result = node.key.compareTo(y.key);
25             if (result < 0) {
26                 y.left = node;
27             } else {
28                 y.right = node;
29             }
30         } else {
31             this.mRoot = node;
32         }
33 
34         node.color = RED;
35 
36         // 插入后修正樹
37         insertFixUp(node);
38     }

輔助修正函數:

 1     /**
 2      * 紅黑樹插入修正函數
 3      *
 4      * @param node
 5      */
 6     private void insertFixUp(RBTNode<T> node) {
 7         RBTNode<T> parent, gparent; // 父節點,祖父節點
 8 
 9         while (((parent = parentOf(node)) != null) && isRed(parent)) {
10             gparent = parentOf(parent);
11 
12             // 父節點是祖父節點的左孩子
13             if (parent == gparent.left) {
14                 RBTNode<T> uncle = gparent.right; // 叔叔節點,祖父的右節點
15 
16                 // ① 叔叔節點是紅色的
17                 if ((uncle != null) && isRed(uncle)) {
18                     node.setColor(BLACK);
19                     parent.setColor(BLACK);
20                     gparent.setColor(RED);
21                     node = gparent;
22                     continue;
23                 }
24 
25                 // ② 叔叔是黑色,且當前節點是右孩子
26                 if (parent.right == node) {
27                     RBTNode<T> tmp;
28                     leftRotate(parent);
29                     tmp = parent;
30                     parent = node;
31                     node = tmp;
32                 }
33 
34                 // ③ 叔叔是黑色,且當前節點是左孩子
35                 parent.setColor(BLACK);
36                 gparent.setColor(RED);
37                 rightRotate(gparent);
38 
39             } else {    // 父節點是祖父節點的右孩子
40 
41                 RBTNode<T> uncle = gparent.left; // 叔叔節點,祖父的左節點
42 
43                 // ① 叔叔節點是紅色的
44                 if ((uncle != null) && isRed(uncle)) {
45                     uncle.setColor(BLACK);
46                     parent.setColor(BLACK);
47                     gparent.setColor(RED);
48                     node = gparent;
49                     continue;
50                 }
51 
52                 // ② 叔叔是黑色,且當前節點是左孩子
53                 if (parent.left == node) {
54                     RBTNode<T> tmp;
55                     rightRotate(parent);
56                     tmp = parent;
57                     parent = node;
58                     node = tmp;
59                 }
60 
61                 // ③ 叔叔是黑色,且當前節點是右孩子
62                 parent.setColor(BLACK);
63                 gparent.setColor(RED);
64                 leftRotate(gparent);
65             }
66         }
67 
68         this.mRoot.setColor(BLACK);
69     }

修正過程實例:

以下圖中的 z 為插入后的結點,y 表示叔結點uncle,圖中的每個子樹的低端的節點是紅黑樹代碼中的邊界,邊界中每個節點有黑色的哨兵沒有畫出來。

 

下面是介紹的是上面代碼中 父節點是祖父節點的左孩子 的代碼。

 

先看圖中的第一個樹,插入的 z 結點和 z.parent 父節點都是 RED,這違反了性質四。

情況 1(得到的是圖中的第二個樹):由於圖中的第一個樹中叔結點是紅色,z 結點和 z.parent 父節點都是 RED結點都要被重新着色,並沿着指針 z 上升;

情況 2(得到的是圖中的第三個樹):由於圖中的第二個樹中 z 及其父節點 z.parent 都為紅色,其叔結點為黑色,左旋父節點 z.parent后得到;

情況 3(得到的是圖中的第四個樹):z 是其父節點的左孩子,重新着色后右旋的到圖中的第四個樹,這樣之后就是合法的紅黑樹了。

分析紅黑樹的插入時間復雜度:

一顆具有 n 個節點的紅黑樹高度為O(log n),則按照一個普通的二叉查找樹的方式插入結點需要花費 O(log n);修正代碼中,當情況 1發生,指針 z沿着樹上升2層,才會執行 while 循環,while 循環可能執行的總次數為 O(log n)。所以紅黑樹的插入的總的時間復雜度為 O(log n)。此外,插入算法中總的來說旋轉次數不超過 2 次。

紅黑樹的刪除:

 1     /**
 2      * 刪除樹中某個節點
 3      *
 4      * @param node 要刪除的結點
 5      */
 6     private void remove(RBTNode<T> node) {
 7         RBTNode<T> child, parent;
 8         boolean color;
 9 
10         // 要刪除的結點node有2個子結點
11         if ((node.left != null) && (node.right != null)) {
12             RBTNode<T> replace = node;
13 
14             // 尋找后繼結點
15             replace = replace.right;
16             while (replace.left != null) {
17                 replace = replace.left;
18             }
19 
20             // 判斷刪除的結點是不是根結點
21             if (parentOf(node) != null) {
22                 if (parentOf(node).left == node) {
23                     parentOf(node).left = replace;
24                 } else {
25                     parentOf(node).right = replace;
26                 }
27             } else {
28                 this.mRoot = replace;
29             }
30 
31 
32             child = replace.right; // 后繼結點的右孩子?左孩子呢?左孩子有早就是后繼結點了,所以直接看后繼結點還有沒有右孩子
33             parent = parentOf(replace); // 后繼結點的父結點
34             color = replace.color;  // 后繼結點的顏色
35 
36             // 要刪除的結點node是后繼結點的父結點
37             if (parent == node) {
38                 parent = replace;   // 這里應該后繼結點直接替換node,留下后繼結點的右子樹
39             } else {    // 后繼結點的父結點不是要刪除的結點node
40                 // 后繼結點的孩子不為空
41                 if (child != null)
42                     child.setParent(parent); // 把<后繼結點的右孩子>的<父結點>設為<后繼結點的父結點>
43                 parent.left = child;    // <后繼結點的父結點>的<左孩子>指向<后繼結點的右孩子>
44 
45                 replace.right = node.right; // 后繼結點的右孩子指向刪除結點的右子樹
46                 node.right.setParent(replace);  //刪除結點的右子樹的父結點設置為后繼結點
47             }
48 
49             replace.parent = node.parent;
50             replace.color = node.color;
51             replace.left = node.left;
52             node.left.parent = replace;
53 
54             if (color == BLACK)
55                 removeFixup(child, parent);
56 
57             node = null;
58 
59             return;
60         }
61 
62         // 選一個要刪除的結點的孩子
63         if (node.left != null) {
64             child = node.left;
65         } else {
66             child = node.right;
67         }
68 
69         parent = node.parent;
70         color = node.color;
71 
72         // 要刪除的結點的孩子不為空
73         if (child != null)
74             child.parent = parent;
75 
76         // 要刪除的結點的父結點是不是樹根
77         if (parent != null) {
78             if (parent.left == node) {
79                 parent.left = child;
80             } else {
81                 parent.right = child;
82             }
83         } else {
84             this.mRoot = child;
85         }
86 
87         if (color == BLACK)
88             removeFixup(child, parent);
89 
90         node = null;
91     }
View Code

 

刪除修正函數:

 1     /**
 2      * 刪除修正函數
 3      *
 4      * @param x
 5      * @param parent
 6      */
 7     private void removeFixup(RBTNode<T> x, RBTNode<T> parent) {
 8         RBTNode<T> w;
 9 
10         while ((x == null || isBlack(x)) && (x != this.mRoot)) {
11             if (parent.left == x) {
12                 w = parent.right;
13 
14                 // ① x的兄弟結點w是紅色的
15                 if (isRed(w)) {
16                     w.setColor(BLACK); // w染黑
17                     parent.setColor(RED);
18                     leftRotate(parent);
19                     w = parent.right;
20                 }
21 
22                 // ② x的兄弟結點w是黑色的,而且w的兩個孩子結點都是黑色的
23                 if ((w.left == null || isBlack(w.left)) &&
24                         (w.right == null || isBlack(w.right))) {
25                     w.setColor(RED);
26                     x = parent;
27                     parent = parentOf(x);
28 
29                 } else {
30 
31                     // ③ x的兄弟結點w是黑色的,w的右孩子是黑色的,w的左孩子是紅色的
32                     if ((w.right == null || isBlack(w.right)) &&
33                             (w.left == null || isBlack(w.left))) {
34                         w.left.setColor(BLACK);
35                         w.setColor(RED);
36                         rightRotate(w);
37                         w = parent.right;
38                     }
39 
40                     // ④ x的兄弟結點w是黑色的,w的右孩子是紅色的
41                     w.setColor(parent.color);
42                     parent.setColor(BLACK);
43                     w.right.setColor(BLACK);
44                     leftRotate(parent);
45                     x = this.mRoot;
46 
47                     break;
48                 }
49 
50             } else {
51 
52                 w = parent.left;
53                 // ① x的兄弟結點w是紅色的
54                 if (isRed(w)) {
55                     w.setColor(BLACK);
56                     parent.setColor(RED);
57                     rightRotate(parent);
58                     w = parent.left;
59                 }
60 
61                 // ②  x的兄弟結點w是黑色的,而且w的兩個孩子結點都是黑色的
62                 if ((w.left == null || isBlack(w.left)) &&
63                         (w.right == null || isBlack(w.right))) {
64                     w.setColor(RED);
65                     x = parent;
66                     parent = parentOf(x);
67                 } else {
68 
69                     // ③ x的兄弟結點w是黑色的,w的右孩子是黑色的,w的左孩子是紅色的
70                     if (w.left == null || isBlack(w.left)) {
71                         w.right.setColor(BLACK);
72                         w.setColor(RED);
73                         leftRotate(w);
74                         w = parent.left;
75                     }
76 
77                     // ④ x的兄弟結點w是黑色的,w的右孩子是紅色的
78                     w.setColor(parent.color);
79                     parent.setColor(BLACK);
80                     w.left.setColor(BLACK);
81                     rightRotate(parent);
82                     x = this.mRoot;
83 
84                     break;
85                 }
86             }
87         }
88 
89         if (x != null)
90             x.setColor(BLACK);
91     }
View Code

 

紅黑樹總的代碼(包含測試代碼):

 

  1 package tree;
  2 
  3 /**
  4  * @program: MyPractice
  5  * @description: 紅黑樹
  6  * @author: Mr.Wu
  7  * @create: 2019-08-28 17:19
  8  **/
  9 public class RBTree<T extends Comparable<T>> {
 10     // 根節點
 11     private RBTNode<T> mRoot;
 12 
 13     private static final boolean RED = false;
 14     private static final boolean BLACK = true;
 15 
 16     private static final int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};
 17     private static final boolean mDebugInsert = false;
 18     private static final boolean mDebugDelete = true;
 19 
 20     /**
 21      * 左旋
 22      * 左旋示意圖(對節點x進行左旋):
 23      * px                               px
 24      * /                                /
 25      * x                                y
 26      * / \          --(左旋)-->         /  \
 27      * lx   y                           x   ry
 28      * / \                        /  \
 29      * ly  ry                     lx   ly
 30      *
 31      * @param x
 32      */
 33     private void leftRotate(RBTNode<T> x) {
 34         RBTNode<T> y = x.right; // y是x的右節點
 35 
 36         x.right = y.left;       // 把y的左節點變為x的右節點
 37         // 若y有左子節點,把y的左節點的父節點換成x
 38         if (y.left != null) {
 39             y.left.parent = x;
 40         }
 41 
 42         y.parent = x.parent;    // y的父節點(原來是x)設為x的父節點
 43 
 44         // 若x是根節點,y直接變根節點
 45         if (x.parent == null) {
 46             this.mRoot = y;
 47         } else {
 48             if (x.parent.left == x) {
 49                 x.parent.left = y;  // 如果x是x父節點的左孩子,把x的父節點的左孩子指向y
 50             } else {
 51                 x.parent.right = y; // 如果x是x父節點的右孩子,把x的父節點的右孩子指向y
 52             }
 53         }
 54 
 55         y.left = x;     // 將y的左節點指向x
 56         x.parent = y;   // 將x的父節點設為y
 57     }
 58 
 59     /**
 60      * 右旋,操作和左旋相反
 61      * 右旋示意圖(對節點y進行左旋):
 62      * py                              py
 63      * /                                /
 64      * y                                x
 65      * / \          --(右旋)-->         /  \
 66      * x  ry                           lx   y
 67      * / \                                  / \
 68      * lx  rx                               rx  ry
 69      *
 70      * @param y
 71      */
 72     private void rightRotate(RBTNode<T> y) {
 73         RBTNode<T> x = y.left;  // y的左孩子
 74 
 75         y.left = x.right;
 76         if (x.right != null) {
 77             x.right.parent = y;
 78         }
 79 
 80         x.parent = y.parent;
 81 
 82         if (y.parent == null) {
 83             this.mRoot = x;
 84         } else {
 85             if (y.parent.left == y) {
 86                 y.parent.left = x;
 87             } else {
 88                 y.parent.right = x;
 89             }
 90         }
 91 
 92         x.right = y;
 93         y.parent = x;
 94     }
 95 
 96     /**
 97      * 插入結點
 98      *
 99      * @param key
100      */
101     public void insert(T key) {
102         RBTNode<T> node = new RBTNode<>(BLACK, key, null, null, null);
103         if (node != null) {
104             insert(node);
105         }
106     }
107 
108     /**
109      * 插入操作
110      *
111      * @param node
112      */
113     private void insert(RBTNode<T> node) {
114         int result;
115         RBTNode<T> y = null;
116         RBTNode<T> x = this.mRoot;
117 
118         // 查找樹中插入點的父結點y的位置
119         while (x != null) {
120             y = x;  // 注意這里,y不是空的
121             result = node.key.compareTo(x.key);
122             if (result < 0) {
123                 x = x.left;
124             } else {
125                 x = x.right;
126             }
127         }
128 
129         node.parent = y;
130         if (y != null) {
131             result = node.key.compareTo(y.key);
132             if (result < 0) {
133                 y.left = node;
134             } else {
135                 y.right = node;
136             }
137         } else {
138             this.mRoot = node;
139         }
140 
141         node.color = RED;
142 
143         // 插入后修正樹
144         insertFixUp(node);
145     }
146 
147     /**
148      * 紅黑樹插入修正函數
149      *
150      * @param node
151      */
152     private void insertFixUp(RBTNode<T> node) {
153         RBTNode<T> parent, gparent; // 父節點 與 祖父節點
154 
155         while (((parent = parentOf(node)) != null) && isRed(parent)) {
156             gparent = parentOf(parent);
157 
158             // 父節點是祖父節點的左孩子
159             if (parent == gparent.left) {
160                 RBTNode<T> uncle = gparent.right; // 叔叔節點,祖父的右節點
161 
162                 // ① 叔叔節點是紅色的
163                 if ((uncle != null) && isRed(uncle)) {
164                     node.setColor(BLACK);
165                     parent.setColor(BLACK);
166                     gparent.setColor(RED);
167                     node = gparent;
168                     continue;
169                 }
170 
171                 // ② 叔叔是黑色,且當前節點是右孩子
172                 if (parent.right == node) {
173                     RBTNode<T> tmp;
174                     leftRotate(parent);
175                     tmp = parent;
176                     parent = node;
177                     node = tmp;
178                 }
179 
180                 // ③ 叔叔是黑色,且當前節點是左孩子
181                 parent.setColor(BLACK);
182                 gparent.setColor(RED);
183                 rightRotate(gparent);
184 
185             } else {    // 父節點是祖父節點的右孩子
186 
187                 RBTNode<T> uncle = gparent.left; // 叔叔節點,祖父的左節點
188 
189                 // ① 叔叔節點是紅色的
190                 if ((uncle != null) && isRed(uncle)) {
191                     uncle.setColor(BLACK);
192                     parent.setColor(BLACK);
193                     gparent.setColor(RED);
194                     node = gparent;
195                     continue;
196                 }
197 
198                 // ② 叔叔是黑色,且當前節點是左孩子
199                 if (parent.left == node) {
200                     RBTNode<T> tmp;
201                     rightRotate(parent);
202                     tmp = parent;
203                     parent = node;
204                     node = tmp;
205                 }
206 
207                 // ③ 叔叔是黑色,且當前節點是右孩子
208                 parent.setColor(BLACK);
209                 gparent.setColor(RED);
210                 leftRotate(gparent);
211             }
212         }
213 
214         this.mRoot.setColor(BLACK);
215     }
216 
217     /**
218      * 刪除樹中某個值
219      *
220      * @param key
221      */
222     public void remove(T key) {
223         RBTNode<T> node;
224 
225         if ((node = search(mRoot, key)) != null)
226             remove(node);
227     }
228 
229     /**
230      * 刪除樹中某個節點
231      *
232      * @param node 要刪除的結點
233      */
234     private void remove(RBTNode<T> node) {
235         RBTNode<T> child, parent;
236         boolean color;
237 
238         // 要刪除的結點node有2個子結點
239         if ((node.left != null) && (node.right != null)) {
240             RBTNode<T> replace = node;
241 
242             // 尋找后繼結點
243             replace = replace.right;
244             while (replace.left != null) {
245                 replace = replace.left;
246             }
247 
248             // 判斷刪除的結點是不是根結點
249             if (parentOf(node) != null) {
250                 if (parentOf(node).left == node) {
251                     parentOf(node).left = replace;
252                 } else {
253                     parentOf(node).right = replace;
254                 }
255             } else {
256                 this.mRoot = replace;
257             }
258 
259 
260             child = replace.right; // 后繼結點的右孩子?左孩子呢?左孩子有早就是后繼結點了,所以直接看后繼結點還有沒有右孩子
261             parent = parentOf(replace); // 后繼結點的父結點
262             color = replace.color;  // 后繼結點的顏色
263 
264             // 要刪除的結點node是后繼結點的父結點
265             if (parent == node) {
266                 parent = replace;   // 這里應該后繼結點直接替換node,留下后繼結點的右子樹
267             } else {    // 后繼結點的父結點不是要刪除的結點node
268                 // 后繼結點的孩子不為空
269                 if (child != null)
270                     child.setParent(parent); // 把<后繼結點的右孩子>的<父結點>設為<后繼結點的父結點>
271                 parent.left = child;    // <后繼結點的父結點>的<左孩子>指向<后繼結點的右孩子>
272 
273                 replace.right = node.right; // 后繼結點的右孩子指向刪除結點的右子樹
274                 node.right.setParent(replace);  //刪除結點的右子樹的父結點設置為后繼結點
275             }
276 
277             replace.parent = node.parent;
278             replace.color = node.color;
279             replace.left = node.left;
280             node.left.parent = replace;
281 
282             if (color == BLACK)
283                 removeFixup(child, parent);
284 
285             node = null;
286 
287             return;
288         }
289 
290         // 選一個要刪除的結點的孩子
291         if (node.left != null) {
292             child = node.left;
293         } else {
294             child = node.right;
295         }
296 
297         parent = node.parent;
298         color = node.color;
299 
300         // 要刪除的結點的孩子不為空
301         if (child != null)
302             child.parent = parent;
303 
304         // 要刪除的結點的父結點是不是樹根
305         if (parent != null) {
306             if (parent.left == node) {
307                 parent.left = child;
308             } else {
309                 parent.right = child;
310             }
311         } else {
312             this.mRoot = child;
313         }
314 
315         if (color == BLACK)
316             removeFixup(child, parent);
317 
318         node = null;
319     }
320 
321     /**
322      * 刪除修正函數
323      *
324      * @param x
325      * @param parent
326      */
327     private void removeFixup(RBTNode<T> x, RBTNode<T> parent) {
328         RBTNode<T> w;
329 
330         while ((x == null || isBlack(x)) && (x != this.mRoot)) {
331             if (parent.left == x) {
332                 w = parent.right;
333 
334                 // ① x的兄弟結點w是紅色的
335                 if (isRed(w)) {
336                     w.setColor(BLACK); // w染黑
337                     parent.setColor(RED);
338                     leftRotate(parent);
339                     w = parent.right;
340                 }
341 
342                 // ② x的兄弟結點w是黑色的,而且w的兩個孩子結點都是黑色的
343                 if ((w.left == null || isBlack(w.left)) &&
344                         (w.right == null || isBlack(w.right))) {
345                     w.setColor(RED);
346                     x = parent;
347                     parent = parentOf(x);
348 
349                 } else {
350 
351                     // ③ x的兄弟結點w是黑色的,w的右孩子是黑色的,w的左孩子是紅色的
352                     if ((w.right == null || isBlack(w.right)) &&
353                             (w.left == null || isBlack(w.left))) {
354                         w.left.setColor(BLACK);
355                         w.setColor(RED);
356                         rightRotate(w);
357                         w = parent.right;
358                     }
359 
360                     // ④ x的兄弟結點w是黑色的,w的右孩子是紅色的
361                     w.setColor(parent.color);
362                     parent.setColor(BLACK);
363                     w.right.setColor(BLACK);
364                     leftRotate(parent);
365                     x = this.mRoot;
366 
367                     break;
368                 }
369 
370             } else {
371 
372                 w = parent.left;
373                 // ① x的兄弟結點w是紅色的
374                 if (isRed(w)) {
375                     w.setColor(BLACK);
376                     parent.setColor(RED);
377                     rightRotate(parent);
378                     w = parent.left;
379                 }
380 
381                 // ②  x的兄弟結點w是黑色的,而且w的兩個孩子結點都是黑色的
382                 if ((w.left == null || isBlack(w.left)) &&
383                         (w.right == null || isBlack(w.right))) {
384                     w.setColor(RED);
385                     x = parent;
386                     parent = parentOf(x);
387                 } else {
388 
389                     // ③ x的兄弟結點w是黑色的,w的右孩子是黑色的,w的左孩子是紅色的
390                     if (w.left == null || isBlack(w.left)) {
391                         w.right.setColor(BLACK);
392                         w.setColor(RED);
393                         leftRotate(w);
394                         w = parent.left;
395                     }
396 
397                     // ④ x的兄弟結點w是黑色的,w的右孩子是紅色的
398                     w.setColor(parent.color);
399                     parent.setColor(BLACK);
400                     w.left.setColor(BLACK);
401                     rightRotate(parent);
402                     x = this.mRoot;
403 
404                     break;
405                 }
406             }
407         }
408 
409         if (x != null)
410             x.setColor(BLACK);
411     }
412 
413     private boolean isRed(RBTNode<T> node) {
414         return (node != null) && (node.color == RED);
415     }
416 
417     private boolean isBlack(RBTNode<T> node) {
418         return !isRed(node);
419     }
420 
421     /**
422      * 二叉查找,遞歸
423      *
424      * @param x
425      * @param key
426      * @return
427      */
428     private RBTNode<T> search(RBTNode<T> x, T key) {
429         if (x == null)
430             return x;
431 
432         int result = key.compareTo(x.key);
433         if (result < 0) {
434             return search(x.left, key);
435         } else if (result > 0) {
436             return search(x.right, key);
437         } else {
438             return x;
439         }
440     }
441 
442     /**
443      * 找結點的父節點
444      *
445      * @param node
446      * @return
447      */
448     private RBTNode<T> parentOf(RBTNode<T> node) {
449         return (node != null) ? node.parent : null;
450     }
451 
452     /**
453      * 置空樹
454      */
455     public void clear() {
456         destroy(mRoot);
457         mRoot = null;
458     }
459 
460     /**
461      * 銷毀樹
462      *
463      * @param tree
464      */
465     private void destroy(RBTNode<T> tree) {
466         if (tree == null) {
467             return;
468         }
469         if (tree.left != null) {
470             destroy(tree.left);
471         }
472         if (tree.right != null) {
473             destroy(tree.right);
474         }
475 
476         tree = null;
477     }
478 
479     /**
480      * 先序遍歷
481      */
482     public void preOrder() {
483         preOrder(mRoot);
484     }
485 
486     /**
487      * 先序遍歷
488      *
489      * @param tree
490      */
491     private void preOrder(RBTNode<T> tree) {
492         if (tree != null) {
493             System.out.print(tree.key + " ");
494             preOrder(tree.left);
495             preOrder(tree.right);
496         }
497     }
498 
499     public void inOrder() {
500         inOrder(mRoot);
501     }
502 
503     /**
504      * 中序遍歷
505      *
506      * @param tree
507      */
508     private void inOrder(RBTNode<T> tree) {
509         if (tree != null) {
510             inOrder(tree.left);
511             System.out.print(tree.key + " ");
512             inOrder(tree.right);
513         }
514     }
515 
516     /**
517      * 后序遍歷
518      */
519     public void postOrder() {
520         postOrder(mRoot);
521     }
522 
523     /**
524      * 后序遍歷
525      *
526      * @param tree
527      */
528     private void postOrder(RBTNode<T> tree) {
529         if (tree != null) {
530             postOrder(tree.left);
531             postOrder(tree.right);
532             System.out.print(tree.key + " ");
533         }
534     }
535 
536     /**
537      * 打印樹的信息
538      */
539     public void print() {
540         if (mRoot != null) {
541             print(mRoot, mRoot.key, 0);
542         }
543     }
544 
545     /**
546      * 打印樹的詳細信息
547      *
548      * @param tree
549      * @param key
550      * @param direction
551      */
552     private void print(RBTNode<T> tree, T key, int direction) {
553         if (tree != null) {
554             if (direction == 0) {
555                 System.out.printf("%2d(B) is root\n", tree.key);
556             } else {
557                 System.out.printf("%2d(%s) is %2d's %6s child\n", tree.key, isRed(tree) ? "R" : "B",
558                         key, direction == 1 ? "right" : "left");
559             }
560             print(tree.left, tree.key, -1);
561             print(tree.right, tree.key, 1);
562         }
563     }
564 
565     /**
566      * 找樹中值最大的結點
567      *
568      * @param tree
569      * @return
570      */
571     private RBTNode<T> maximum(RBTNode<T> tree) {
572         if (tree == null)
573             return null;
574         while (tree.right != null)
575             tree = tree.right;
576         return null;
577     }
578 
579     /**
580      * 找樹中值最大的結點
581      *
582      * @return
583      */
584     public T maximum() {
585         RBTNode<T> p = maximum(mRoot);
586         if (p != null)
587             return p.key;
588         return null;
589     }
590 
591     /**
592      * 找樹中值最小的結點
593      *
594      * @param tree
595      * @return
596      */
597     private RBTNode<T> minimum(RBTNode<T> tree) {
598         if (tree == null)
599             return null;
600         while (tree.left != null)
601             tree = tree.left;
602         return tree;
603     }
604 
605     /**
606      * 找樹中值最小的結點
607      */
608     public T minimum() {
609         RBTNode<T> p = minimum(mRoot);
610         if (p != null)
611             return p.key;
612         return null;
613     }
614 
615     /**
616      * 測試主函數
617      * @param args
618      */
619     public static void main(String[] args) {
620         int i, length = a.length;
621         RBTree<Integer> tree = new RBTree<>();
622 
623         System.out.printf("== 原始數據: ");
624         for (i = 0; i < length; i++)
625             System.out.printf("%d ", a[i]);
626         System.out.printf("\n");
627 
628         for (i = 0; i < length; i++) {
629             tree.insert(a[i]);
630             // 設置mDebugInsert=true,測試"添加函數"
631             if (mDebugInsert) {
632                 System.out.printf("== 添加節點: %d\n", a[i]);
633                 System.out.printf("== 樹的詳細信息: \n");
634                 tree.print();
635                 System.out.printf("\n");
636             }
637         }
638 
639         System.out.printf("== 前序遍歷: ");
640         tree.preOrder();
641 
642         System.out.printf("\n== 中序遍歷: ");
643         tree.inOrder();
644 
645         System.out.printf("\n== 后序遍歷: ");
646         tree.postOrder();
647 
648         System.out.printf("\n");
649 
650         System.out.printf("== 最小值: %s\n", tree.minimum());
651         System.out.printf("== 最大值: %s\n", tree.maximum());
652         System.out.printf("== 樹的詳細信息: \n");
653         tree.print();
654 
655         System.out.printf("\n");
656 
657         // 設置mDebugDelete=true,測試"刪除函數"
658         if (mDebugDelete) {
659             for (i = 0; i < length; i++) {
660                 tree.remove(a[i]);
661 
662                 System.out.printf("== 刪除節點: %d\n", a[i]);
663                 System.out.printf("== 樹的詳細信息: \n");
664                 tree.print();
665 
666                 System.out.printf("\n");
667             }
668         }
669 
670         // 銷毀二叉樹
671         tree.clear();
672     }
673 
674     /** 紅黑樹結點 RBTNode **/
675     public class RBTNode<T extends Comparable<T>> {
676         boolean color;   // 顏色
677         T key;           // 關鍵字
678         RBTNode<T> left;
679         RBTNode<T> right;
680         RBTNode<T> parent;
681 
682         public RBTNode(boolean color, T key, RBTNode<T> left, RBTNode<T> right, RBTNode<T> parent) {
683             this.color = color;
684             this.key = key;
685             this.left = left;
686             this.right = right;
687             this.parent = parent;
688         }
689 
690         public boolean isColor() {
691             return color;
692         }
693 
694         public void setColor(boolean color) {
695             this.color = color;
696         }
697 
698         public T getKey() {
699             return key;
700         }
701 
702         public void setKey(T key) {
703             this.key = key;
704         }
705 
706         public RBTNode<T> getLeft() {
707             return left;
708         }
709 
710         public void setLeft(RBTNode<T> left) {
711             this.left = left;
712         }
713 
714         public RBTNode<T> getRight() {
715             return right;
716         }
717 
718         public void setRight(RBTNode<T> right) {
719             this.right = right;
720         }
721 
722         public RBTNode<T> getParent() {
723             return parent;
724         }
725 
726         public void setParent(RBTNode<T> parent) {
727             this.parent = parent;
728         }
729     }
730 }
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM