红黑树的实现

红黑树,AVL 树,B/B+ 树这三个树很经典,之前一直都想手动实现。今天撸了一下红黑树,说实话红黑树比我之前写 AVL 树繁琐多了,看着别人的代码,修修补补也弄了我好久。。

红黑树的介绍

Red-Black Tree,就是一个特殊的二叉查找树,AVL 通过自调整树高度来保证数据操作控制在 O(logn) ,红黑树则通过颜色来变相调整高度来保证时间复杂度不会退化成链表。

很多地方都应用了红黑树,Java 里的 TreeMap, C++ 里的 map, linux 里的进程调度都用到了红黑树。

5 个特性:

  1. 每个节点或者是黑色,或者是红色。
  2. 根节点是黑色。
  3. 每个叶子节点是黑色。 [注意: 这里叶子节点,是指为空的叶子节点!]
  4. 如果一个节点是红色的,则它的子节点必须是黑色的。
  5. 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

红黑树的 Java 实现

基本操作就是旋转,添加和删除。红黑树结点就是一个二叉树结点加上一个颜色和一个指向父结点的指针。

旋转

旋转就是左旋和右旋。

左旋。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 
* 对红黑树的节点(x)进行左旋转
*
* 左旋示意图(对节点x进行左旋):
* px px
* / /
* x y
* / \ --(左旋)-. / \ #
* lx y x ry
* / \ / \
* ly ry lx ly
*
*
*/

右旋。

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 
* 对红黑树的节点(y)进行右旋转
*
* 右旋示意图(对节点y进行左旋):
* py py
* / /
* y x
* / \ --(右旋)-. / \ #
* x ry lx y
* / \ / \ #
* lx rx rx ry
*
*/

添加

  1. 将红黑树当作一颗二叉查找树,将节点插入。
  2. 将插入的节点着色为”红色”。
  3. 通过一系列的旋转或着色等操作,使之重新成为一颗红黑树。

此时当插入结点的父结点为红色的时候,违背了规则 4如果一个节点是红色的,则它的子节点必须是黑色的,需要调整。此时祖父结点必为黑色,又可以分成 3 种情况来调整。

now 为当前插入的结点,B 为黑色结点,R 为红色结点。

  1. 叔叔结点为红色,直接把父结点和叔叔结点变成黑色就可以了,祖父结点编程红色,然后 now 变成祖父结点继续向上递归。

    1
    2
    3
    4
    5
    6
    7
    *           py                               py
    * / /
    * B R
    * / \ / \
    * R R B B
    * / /
    * now now
  2. 叔叔结点是黑色,当前结点是父结点的右孩子。左旋父结点,然后 now 变成之前原来的父结点。的使其变成情况 3

    1
    2
    3
    4
    5
    6
    7
    *           py                               py
    * / /
    * B B
    * / \ / \
    * R B 左旋parent now B
    * \ /
    * now R
  3. 叔叔结点是黑色,当前结点是父结点的左孩子。父结点变黑,祖父结点变红,右旋祖父结点。

    1
    2
    3
    4
    5
    6
    7
    *           py                   py                 py
    * / / /
    * B R B
    * / \ / \ / \
    * R B B B now R
    * / / \
    * now now B

还有右边的情况,是对称的,就不举例了。

删除

  1. 将红黑树当作一颗二叉查找树,将节点删除。
    • 被删除节点没有儿子,即为叶节点。那么,直接将该节点删除就OK了。
    • 被删除节点只有一个儿子。那么,直接删除该节点,并用该节点的唯一子节点顶替它的位置。
    • 被删除节点有两个儿子。那么,先找出它的后继节点(后继结点就是树中下一个大于这个数的数);然后把“它的后继节点的内容”复制给“该节点的内容”;之后,删除“它的后继节点”。
  2. 通过”旋转和重新着色”等一系列来修正该树,使之重新成为一棵红黑树。

如果删除的结点是黑色的,则需要调整。可以分成 4 中情况来调整。

now 必为黑色

  1. 兄弟结点为红色。兄弟结点变黑,父结点变红,左旋父结点。易得此时兄弟结点必为黑,转化成其他情况。

    1
    2
    3
    4
    5
    6
    7
    *           py              py          py
    * / / /
    * B R B
    * / \ / \ /
    * now R now B R
    * /
    * now
  2. 兄弟结点为黑,并且兄弟结点两个孩子也是黑的。兄弟结点变红,now 变成父结点向上递归。

    1
    2
    3
    4
    5
    6
    7
    *           py              py         
    * / /
    * B/R B/R
    * / \ / \
    * now B now R
    * / \ / \
    * B B B B
  3. 兄弟结点为黑,并且左孩子为红。左孩子变黑,兄弟结点变红,右旋兄弟结点,变成情况4

    1
    2
    3
    4
    5
    6
    7
    8
    9
    *           py              py          py
    * / / /
    * B/R B/R B/R
    * / \ / \ / \
    * now B now R now B
    * / \ / \ \
    * R B B B R
    * \
    * B
  4. 兄弟结点为黑,并且右孩子为红,左孩子为任意颜色。兄弟结点改成父结点的颜色,父结点变黑,兄弟结点的右孩子变黑,左旋父结点。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    *           py              py             py
    * / / /
    * B/R B B/R
    * / \ / \ / \
    * now B now B/R B B
    * \ \ /
    * R B now
    *
    *

还有对称的情况。其实这么多情况还是有点恶心人的。

Java 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
public class RBTree<T extends Comparable<T>> {

private RBTNode<T> mRoot; // 根结点

private static final boolean RED = false;
private static final boolean BLACK = true;

public class RBTNode<T extends Comparable<T>> {
boolean color; // 颜色
T key; // 键值
RBTNode<T> left; // 左孩子
RBTNode<T> right; // 右孩子
RBTNode<T> parent; // 父结点

public RBTNode(T key, boolean color, RBTNode<T> parent, RBTNode<T> left, RBTNode<T> right)
{
this.key = key;
this.color = color;
this.parent = parent;
this.left = left;
this.right = right;
}

public T getKey()
{
return key;
}

public String toString()
{
return "" + key + (this.color==RED ? "R" : "B");
}
}

public RBTree()
{
mRoot = null;
}

private RBTNode<T> parentOf(RBTNode<T> node)
{
return node != null ? node.parent : null;
}

private boolean colorOf(RBTNode<T> node)
{
return node != null ? node.color : BLACK;
}

private boolean isRed(RBTNode<T> node)
{
return (node != null) && (node.color == RED) ? true : false;
}

private boolean isBlack(RBTNode<T> node)
{
return !isRed(node);
}

private void setBlack(RBTNode<T> node)
{
if(node != null)
node.color = BLACK;
}

private void setRed(RBTNode<T> node)
{
if(node != null)
node.color = RED;
}

private void setParent(RBTNode<T> node, RBTNode<T> parent)
{
if(node != null)
node.parent = parent;
}

private void setColor(RBTNode<T> node, boolean color)
{
if(node != null)
node.color = color;
}

/*
* 前序遍历"红黑树"
*/
private void preOrder(RBTNode<T> tree)
{
if(tree != null)
{
System.out.print(tree.key + " ");
preOrder(tree.left);
preOrder(tree.right);
}
}

public void preOrder()
{
preOrder(mRoot);
}

/*
* 中序遍历"红黑树"
*/
private void inOrder(RBTNode<T> tree) {
if(tree != null) {
inOrder(tree.left);
System.out.print(tree.key+" ");
inOrder(tree.right);
}
}

public void inOrder() {
inOrder(mRoot);
}


/*
* 后序遍历"红黑树"
*/
private void postOrder(RBTNode<T> tree) {
if(tree != null)
{
postOrder(tree.left);
postOrder(tree.right);
System.out.print(tree.key+" ");
}
}

/*
* (递归实现)查找"红黑树x"中键值为key的节点
*/
private RBTNode<T> search(RBTNode<T> x, T key) {
if (x==null)
return x;

int cmp = key.compareTo(x.key);
if (cmp < 0)
return search(x.left, key);
else if (cmp > 0)
return search(x.right, key);
else
return x;
}

public RBTNode<T> search(T key) {
return search(mRoot, key);
}

/*
* (非递归实现)查找"红黑树x"中键值为key的节点
*/
private RBTNode<T> iterativeSearch(RBTNode<T> x, T key) {
while (x!=null) {
int cmp = key.compareTo(x.key);

if (cmp < 0)
x = x.left;
else if (cmp > 0)
x = x.right;
else
return x;
}

return x;
}

public RBTNode<T> iterativeSearch(T key) {
return iterativeSearch(mRoot, key);
}

/*
* 找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。
*/
public RBTNode<T> successor(RBTNode<T> x) {
// 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
if (x.right != null)
return minimum(x.right);

// 如果x没有右孩子。则x有以下两种可能:
// (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
// (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。
RBTNode<T> y = x.parent;
while ((y!=null) && (x==y.right)) {
x = y;
y = y.parent;
}

return y;
}

/*
* 找结点(x)的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。
*/
public RBTNode<T> predecessor(RBTNode<T> x) {
// 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
if (x.left != null)
return maximum(x.left);

// 如果x没有左孩子。则x有以下两种可能:
// (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
// (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。
RBTNode<T> y = x.parent;
while ((y!=null) && (x==y.left)) {
x = y;
y = y.parent;
}

return y;
}

/*
* 查找最小结点: 返回tree为根结点的红黑树的最小结点。
*/
private RBTNode<T> minimum(RBTNode<T> tree) {
if (tree == null)
return null;

while(tree.left != null)
tree = tree.left;
return tree;
}

public T minimum() {
RBTNode<T> p = minimum(mRoot);
if (p != null)
return p.key;

return null;
}

/*
* 查找最大结点: 返回tree为根结点的红黑树的最大结点。
*/
private RBTNode<T> maximum(RBTNode<T> tree) {
if (tree == null)
return null;

while(tree.right != null)
tree = tree.right;
return tree;
}

public T maximum() {
RBTNode<T> p = maximum(mRoot);
if (p != null)
return p.key;

return null;
}

public void postOrder() {
postOrder(mRoot);
}

/*
* 对红黑树的节点(x)进行左旋转
*
* 左旋示意图(对节点x进行左旋):
* px px
* / /
* x y
* / \ --(左旋)-. / \ #
* lx y x ry
* / \ / \
* ly ry lx ly
*
*
*/
private void leftRotate(RBTNode<T> x)
{
// x 的右结点
RBTNode<T> y = x.right;

// y 的左孩子给 x 做右孩子
x.right = y.left;
if(y.left != null)
y.left.parent = x;

// x 的 parent 给 y 做 parent
y.parent = x.parent;
if(x.parent == null)
{
this.mRoot = y;
}
else
{
if(x.parent.left == x)
x.parent.left = y;
else
x.parent.right = y;
}

// x 做 y 的左孩子
y.left = x;
x.parent = y;
}

/*
* 对红黑树的节点(y)进行右旋转
*
* 右旋示意图(对节点y进行左旋):
* py py
* / /
* y x
* / \ --(右旋)-. / \ #
* x ry lx y
* / \ / \ #
* lx rx rx ry
*
*/
private void rightRotate(RBTNode<T> y)
{
// x 是 y 的左结点
RBTNode<T> x = y.left;

// x 的右孩子给 y 做左孩子
y.left = x.right;
if(x.right != null)
x.right.parent = y;

// y 的 parent 给 x 做 parent
x.parent = y.parent;
if(y.parent == null)
{
this.mRoot = x;
}
else
{
if(y.parent.left == y)
y.parent.left = x;
else
y.parent.right = x;
}

// y 给 x 做右孩子
y.parent = x;
x.right = y;
}

/*
* 将结点插入到红黑树中
*
* 参数说明:
* node 插入的结点 // 对应《算法导论》中的node
*/
private void insert(RBTNode<T> node)
{
int cmp;
RBTNode<T> y = null;
RBTNode<T> x = this.mRoot;

// 把结点插入二叉查找树
while(x != null)
{
y = x;
cmp = node.key.compareTo(y.key);
if(cmp < 0)
x = x.left;
else
x = x.right;
}

node.parent = y;
if(y != null)
{
cmp = node.key.compareTo(y.key);
if(cmp < 0)
{
y.left = node;
}
else
{
y.right = node;
}
}
else
{
this.mRoot = node;
}

node.color = RED;

insertFixUp(node);
}

/*
* 新建结点(key),并将其插入到红黑树中
*
* 参数说明:
* key 插入结点的键值
*/
public void insert(T key)
{
RBTNode<T> node = new RBTNode<>(key, BLACK, null, null, null);

if(node != null)
insert(node);
}

/*
* 红黑树插入修正函数
*
* 在向红黑树中插入节点之后(失去平衡),再调用该函数;
* 目的是将它重新塑造成一颗红黑树。
*
* 参数说明:
* node 插入的结点 // 对应《算法导论》中的z
*/
private void insertFixUp(RBTNode<T> node)
{
RBTNode<T> parent, gparent;

// 若“父结点存在,并且父结点是红色的”
while(((parent = parentOf(node)) != null) && isRed(parent))
{
gparent = parentOf(parent);

// 若父结点是祖父结点的左孩子
if(parent == gparent.left)
{
// Case1: 叔叔结点是红色
RBTNode<T> uncle = gparent.right;
if(uncle != null && isRed(uncle))
{
setBlack(uncle);
setBlack(parent);
setRed(gparent);
node = gparent;
continue;
}

// Case2: 叔叔是黑色,当前结点是右孩子
if(parent.right == node)
{
RBTNode<T> tmp;
leftRotate(parent);
tmp = parent;
parent = node;
node = tmp;
}

// Case3: 叔叔是黑色,当前结点是左孩子
setBlack(parent);
setRed(gparent);
rightRotate(gparent);
} else { // 父结点是祖父结点的右孩子
// Case1: 叔叔结点是红色
RBTNode<T> uncle = gparent.left;
if (uncle != null && isRed(uncle)) {
setBlack(uncle);
setBlack(parent);
setRed(gparent);
node = gparent;
continue;
}

// Case2: 叔叔结点是黑色,当前结点是左孩子
if (parent.left == node) {
RBTNode<T> tmp;
rightRotate(parent);
tmp = parent;
parent = node;
node = tmp;
}

// Case3: 叔叔结点是黑色,当前结点是右孩子
setBlack(parent);
setRed(gparent);
leftRotate(gparent);
}
}

// 将根结点设为黑色
setBlack(this.mRoot);
}

/*
* 删除结点(node),并返回被删除的结点
*
* 参数说明:
* node 删除的结点
*/
private void remove(RBTNode<T> node)
{
RBTNode<T> child, parent;
boolean color;

// 被删除的结点左右结点都不为空
if(node.left != null && node.right != null)
{
// 后继结点取代该结点,然后删除后继结点
RBTNode<T> replace = node;

// 获取后继结点
replace = replace.right;
while(replace.left != null)
replace = replace.left;

// 更改 parent 的指针
if(parentOf(node) != null)
{
if(parentOf(node).left == node)
{
parentOf(node).left = replace;
}
else
{
parentOf(node).right = replace;
}
}
else
{
this.mRoot = replace;
}

// 把后继结点的右孩子给后继结点的 parent 做左孩子,删除后继结点
child = replace.right;
parent = parentOf(replace);
color = colorOf(replace);
if(parent == node)
{
parent = replace;
}
else
{
if(child != null)
setParent(child, parent);
parent.left = child;

replace.right = node.right;
setParent(node.right, replace);
}

// 用 replace 替换 node
replace.parent = node.parent;
replace.color = node.color;
replace.left = node.left;
node.left.parent = replace;

// 被删除的要是黑色结点,需要调整红黑树
if(color == BLACK)
removeFixUp(child, parent);


node = null;
return;
}

// 获得孩子
if(node.left != null)
{
child = node.left;
}
else
{
child = node.right;
}

// 用孩子替换
parent = node.parent;
color = node.color;

if(child != null)
child.parent = parent;

if(parent != null)
{
if(parent.left == node)
parent.left = child;
else
parent.right = child;
}
else {
this.mRoot = child;
}

// 删除要是黑色结点,调整红黑树
if(color == BLACK)
removeFixUp(child, parent);
node = null;
}

/*
* 删除结点(z),并返回被删除的结点
*
* 参数说明:
* tree 红黑树的根结点
* z 删除的结点
*/
public void remove(T key) {
RBTNode<T> node;

if ((node = search(mRoot, key)) != null)
remove(node);
}

/*
* 红黑树删除修正函数
*
* 在从红黑树中删除插入节点之后(红黑树失去平衡),再调用该函数;
* 目的是将它重新塑造成一颗红黑树。
*
* 参数说明:
* node 待修正的节点
*/
private void removeFixUp(RBTNode<T> node, RBTNode<T> parent)
{
RBTNode<T> other;

while((node == null || isBlack(node)) && node != this.mRoot)
{
if(parent.left == node) // 待修正结点是左孩子
{
other = parent.right;
// Case1: x 的兄弟是红色的
if(isRed(other))
{
setBlack(other);
setRed(parent);
leftRotate(parent);
other = parent.right;
}

// Case2: x 的兄弟是黑色并且两个孩子也是黑色
if(other.left == null || isBlack(other.left) &&
(other.right == null || isBlack(other.right)))
{
setRed(other);
node = parent;
parent = parentOf(node);
}
else
{
// Case3: x 的兄弟是黑色,并且左孩子是红色,右孩子是黑色
if(other.right == null || isBlack(other.right))
{
setBlack(other.left);
setRed(other);
rightRotate(other);
other = parent.right;
}

// Case4: x 的兄弟是黑色,并且右孩子是红色,左孩子是任意颜色
setColor(other, colorOf(parent));
setBlack(parent);
setBlack(other.right);
leftRotate(parent);
node = this.mRoot;
break;
}
}
else // 待修正结点是右孩子
{
other = parent.left;

if(isRed(other)) // Case1: 兄弟结点是红的
{
setBlack(other);
setRed(parent);
rightRotate(parent);
other = parent.left;
}

// 此时 other 必为 BLACK


if((other.left == null || isBlack(other.left) &&
(other.right == null || isBlack(other.right)))) // Case2: 兄弟结点两个孩子都是黑的
{
setRed(other);
node = parent;
parent = parentOf(node);
}
else
{

if(other.left == null || isBlack(other.left))
{
// Case3: 左孩子为黑,右孩子为红
setBlack(other.right);
setRed(other);
leftRotate(other);
other = parent.left;
}

// Case4: 左孩子为红,右孩子任意颜色
setColor(other, colorOf(parent));
setBlack(parent);
setBlack(other.left);
rightRotate(parent);
node = this.mRoot;
break;
}
}
}

if (node!=null)
setBlack(node);
}

/*
* 销毁红黑树
*/
private void destroy(RBTNode<T> tree) {
if (tree==null)
return ;

if (tree.left != null)
destroy(tree.left);
if (tree.right != null)
destroy(tree.right);

tree=null;
}

public void clear() {
destroy(mRoot);
mRoot = null;
}

/*
* 打印"红黑树"
*
* key -- 节点的键值
* direction -- 0,表示该节点是根节点;
* -1,表示该节点是它的父结点的左孩子;
* 1,表示该节点是它的父结点的右孩子。
*/
private void print(RBTNode<T> tree, T key, int direction) {

if(tree != null) {

if(direction==0) // tree是根节点
System.out.printf("%2d(B) is root\n", tree.key);
else // tree是分支节点
System.out.printf("%2d(%s) is %2d's %6s child\n", tree.key, isRed(tree)?"R":"B", key, direction==1?"right" : "left");

print(tree.left, tree.key, -1);
print(tree.right,tree.key, 1);
}
}

public void print() {
if (mRoot != null)
print(mRoot, mRoot.key, 0);
}
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class RBTreeTest {

private static final int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};
private static final boolean mDebugInsert = false; // "插入"动作的检测开关(false,关闭;true,打开)
private static final boolean mDebugDelete = false; // "删除"动作的检测开关(false,关闭;true,打开)

public static void main(String[] args) {
int i, ilen = a.length;
RBTree<Integer> tree=new RBTree<Integer>();

System.out.printf("== 原始数据: ");
for(i=0; i<ilen; i++)
System.out.printf("%d ", a[i]);
System.out.printf("\n");

for(i=0; i<ilen; i++) {
tree.insert(a[i]);
// 设置mDebugInsert=true,测试"添加函数"
if (mDebugInsert) {
System.out.printf("== 添加节点: %d\n", a[i]);
System.out.printf("== 树的详细信息: \n");
tree.print();
System.out.printf("\n");
}
}

System.out.printf("== 前序遍历: ");
tree.preOrder();

System.out.printf("\n== 中序遍历: ");
tree.inOrder();

System.out.printf("\n== 后序遍历: ");
tree.postOrder();
System.out.printf("\n");

System.out.printf("== 最小值: %s\n", tree.minimum());
System.out.printf("== 最大值: %s\n", tree.maximum());
System.out.printf("== 树的详细信息: \n");
tree.print();
System.out.printf("\n");

// 设置mDebugDelete=true,测试"删除函数"
if (mDebugDelete) {
for(i=0; i<ilen; i++)
{
tree.remove(a[i]);

System.out.printf("== 删除节点: %d\n", a[i]);
System.out.printf("== 树的详细信息: \n");
tree.print();
System.out.printf("\n");
}
}

// 销毁二叉树
tree.clear();
}
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
== 原始数据: 10 40 30 60 90 70 20 50 80 
== 前序遍历: 30 10 20 60 40 50 80 70 90
== 中序遍历: 10 20 30 40 50 60 70 80 90
== 后序遍历: 20 10 50 40 70 90 80 60 30
== 最小值: 10
== 最大值: 90
== 树的详细信息:
30(B) is root
10(B) is 30's left child
20(R) is 10's right child
60(R) is 30's right child
40(B) is 60's left child
50(R) is 40's right child
80(B) is 60's right child
70(R) is 80's left child
90(R) is 80's right child


Process finished with exit code 0

参考资料