1、重构二叉搜索树
1.1、设计思想
由于实际项目中常用的二叉树种类有很多(如:二叉搜索树、AVL树、红黑树等),为了提高代码的复用率和可读性,我们可以通过继承二叉树的方式重构这些特殊的二叉树。
因此,我们也可以通过继承二叉树的方式实现二叉搜索树(Binary Search Tree,BST),如下图所示:
 
其中:
- 二叉树类中存放所有二叉树公共的接口。
- 二叉搜索树类中实现二叉搜索树自己特有的接口。
1.2、类的结构设计
同样地,在编程之前,我们需要先对二叉树类和二叉搜索树类的结构进行设计。
1.2.1、二叉树类设计
二叉树类需要的成员主要包括:
**注:**内部类的成员可以不写访问权限。
- 
用户自定义对节点元素的处理逻辑(抽象类) | 12
 3
 4
 5
 6
 7
 8
 
 | public static abstract class Visitor<E>{boolean isStoped;
 
 
 
 
 abstract boolean visit(E element);
 }
 
 |  
 
- 
接口函数 
1.2.2、二叉搜索树类
二叉搜索树类需要的成员主要包括:
1.3、接口设计
1.3.1、二叉树类接口设计
- int size(); 	//元素的数量
- boolean isEmpty();     //是否为空
- void clear();       //清空所有元素
- void preorder();    //前序遍历
- void inorder();    //中序遍历
- void postorder();    //后序遍历
- void levelOrder();    //层序遍历
- boolean isComplete();    //是否为完全二叉树
- int height();    //计算二叉树的高度
注:
- 与动态数组的接口相比,二叉树的元素是没有索引(index)这一概念的。
- 用户处理(添加、删除、查找等)的是元素,他们是不关心二叉树内部节点结构的。
- 由于普通二叉树中各节点之间的逻辑关系不明确,因此实际应用中一般不使用普通二叉树存储数据,而是使用继承了该类的特定二叉树(如:二叉搜索树、AVL树、红黑树等)来存储数据,进行元素的增加、删除、查询等操作。
1.3.2、二叉搜索树类接口设计
- void add(E element);        //添加元素
- void remove(E element);     //删除元素
- boolean contains(E element);     //搜索(查找二叉搜索树中是否包含某元素)
2、重新实现二叉搜索树
2.1、编程实现
新建一个项目,在其中:
(1)★实现二叉树
新建一个名称为BinaryTree(包名为:com.atangbiji)的类,用来实现二叉树;
BinaryTree.java文件:
| 12
 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
 
 | package com.atangbiji;
 import java.util.LinkedList;
 import java.util.Queue;
 import com.atangbiji.printer.BinaryTreeInfo;
 
 
 @SuppressWarnings("unchecked")
 public class BinaryTree<E> implements BinaryTreeInfo{
 
 protected int size;
 protected Node<E> root;
 
 
 protected static class Node<E> {
 E element;
 Node<E> left;
 Node<E> right;
 Node<E> parent;
 
 
 public Node(E element, Node<E> parent) {
 this.element = element;
 this.parent = parent;
 }
 
 
 public boolean isLeaf() {
 return left == null && right == null;
 }
 
 
 public boolean hasTwoChildren() {
 return left != null && right != null;
 }
 }
 
 
 public static abstract class Visitor<E>{
 boolean isStoped;
 
 
 
 
 abstract boolean visit(E element);
 }
 
 
 
 
 
 
 public int size() {
 return size;
 }
 
 
 
 
 
 
 public boolean isEmpty() {
 return size == 0;
 }
 
 
 
 
 
 
 public void clear() {
 root = null;
 size = 0;
 }
 
 
 
 
 
 
 
 public void preorder(Visitor<E> visitor) {
 preorder(root,visitor);
 }
 
 
 
 
 
 private void preorder(Node<E> node, Visitor<E> visitor)  {
 
 if (node == null || visitor == null || visitor.isStoped)
 return;
 
 
 visitor.isStoped = visitor.visit(node.element);
 
 preorder(node.left,visitor);
 
 preorder(node.right,visitor);
 }
 
 
 public void inorder(Visitor<E> visitor) {
 inorder(root,visitor);
 }
 
 
 
 
 
 private void inorder(Node<E> node, Visitor<E> visitor)  {
 
 if (node == null || visitor == null || visitor.isStoped)
 return;
 
 
 inorder(node.left,visitor);
 
 if (visitor.isStoped) return;
 
 visitor.isStoped = visitor.visit(node.element);
 
 inorder(node.right,visitor);
 }
 
 
 public void postorder(Visitor<E> visitor) {
 postorder(root,visitor);
 }
 
 
 
 
 
 private void postorder(Node<E> node, Visitor<E> visitor)  {
 
 if (node == null || visitor == null || visitor.isStoped)
 return;
 
 
 postorder(node.left,visitor);
 
 postorder(node.right,visitor);
 
 if (visitor.isStoped) return;
 
 visitor.isStoped = visitor.visit(node.element);
 }
 
 
 
 
 
 
 public void levelOrder(Visitor<E> visitor) {
 if (root == null || visitor == null)
 return;
 
 Queue<Node<E>> queue = new LinkedList<>();
 queue.offer(root);
 
 while (!queue.isEmpty()) {
 
 Node<E> node = queue.poll();
 
 
 if (visitor.visit(node.element)) {
 return;
 };
 
 if (node.left != null) {
 
 queue.offer(node.left);
 }
 
 if (node.right != null) {
 
 queue.offer(node.right);
 }
 }
 }
 
 
 
 
 
 
 
 public void preorderTraversal() {
 preorderTraversal(root);
 }
 
 
 
 
 
 private void preorderTraversal(Node<E> node)  {
 
 if (node == null)
 return;
 
 
 System.out.println(node.element);
 
 preorderTraversal(node.left);
 
 preorderTraversal(node.right);
 }
 
 
 public void inorderTraversal() {
 inorderTraversal(root);
 }
 
 
 
 
 
 private void inorderTraversal(Node<E> node)  {
 
 if (node == null)
 return;
 
 
 inorderTraversal(node.left);
 
 System.out.println(node.element);
 
 inorderTraversal(node.right);
 }
 
 
 public void postorderTraversal() {
 postorderTraversal(root);
 }
 
 
 
 
 
 private void postorderTraversal(Node<E> node)  {
 
 if (node == null)
 return;
 
 
 postorderTraversal(node.left);
 
 postorderTraversal(node.right);
 
 System.out.println(node.element);
 }
 
 
 
 
 
 
 
 public void levelOrderTraversal() {
 if (root == null)
 return;
 
 Queue<Node<E>> queue = new LinkedList<>();
 queue.offer(root);
 
 while (!queue.isEmpty()) {
 
 Node<E> node = queue.poll();
 System.out.println(node.element);
 
 if (node.left != null) {
 
 queue.offer(node.left);
 }
 
 if (node.right != null) {
 
 queue.offer(node.right);
 }
 }
 }
 
 
 
 
 
 
 protected Node<E> predecessor(Node<E> node) {
 if (node == null) return null;
 
 
 Node<E> p = node.left;
 if (p != null) {
 while (p.right != null) {
 p = p.right;
 }
 return p;
 }
 
 
 while (node.parent != null && node == node.parent.left) {
 node = node.parent;
 }
 
 
 return node.parent;
 }
 
 
 
 
 
 
 protected Node<E> successor(Node<E> node) {
 if (node == null) return null;
 
 
 Node<E> p = node.right;
 if (p != null) {
 while (p.left != null) {
 p = p.left;
 }
 return p;
 }
 
 
 while (node.parent != null && node == node.parent.right) {
 node = node.parent;
 }
 
 return node.parent;
 }
 
 
 
 
 
 
 public boolean isComplete() {
 if (root == null) return false;
 
 Queue<Node<E>> queue = new LinkedList<>();
 queue.offer(root);
 
 boolean leaf = false;
 while (!queue.isEmpty()) {
 Node<E> node = queue.poll();
 if (leaf && !node.isLeaf())
 return false;
 if (node.hasTwoChildren()) {
 queue.offer(node.left);
 queue.offer(node.right);
 } else if (node.left == null && node.right != null) {
 return false;
 } else {
 leaf = true;
 if (node.left != null) {
 queue.offer(node.left);
 }
 }
 }
 return true;
 }
 
 
 
 
 
 
 public boolean isComplete2() {
 if (root == null) return false;
 
 Queue<Node<E>> queue = new LinkedList<>();
 queue.offer(root);
 
 boolean leaf = false;
 while (!queue.isEmpty()) {
 Node<E> node = queue.poll();
 if (leaf && !node.isLeaf())
 return false;
 
 if (node.left != null) {
 queue.offer(node.left);
 } else if (node.right != null) {
 return false;
 }
 
 if (node.right != null) {
 queue.offer(node.right);
 } else {
 leaf = true;
 }
 }
 return true;
 }
 
 
 
 
 
 
 public int height() {
 
 return height(root);
 }
 
 
 
 
 
 
 private int height(Node<E> node) {
 if (node == null) return 0;
 
 return 1 + Math.max(height(node.left), height(node.right));
 }
 
 
 
 
 
 
 public int height2() {
 if (root == null) return 0;
 
 
 int height = 0;
 
 int levelSize = 1;
 Queue<Node<E>> queue = new LinkedList<>();
 queue.offer(root);
 
 while (!queue.isEmpty()) {
 Node<E> node = queue.poll();
 levelSize--;
 
 if (node.left != null) {
 queue.offer(node.left);
 }
 
 if (node.right != null) {
 queue.offer(node.right);
 }
 
 
 if (levelSize == 0) {
 levelSize = queue.size();
 height++;
 }
 }
 
 return height;
 }
 
 
 
 
 
 
 @Override
 public String toString() {
 StringBuilder sb = new StringBuilder();
 
 
 toString(root,sb,"");
 
 return sb.toString();
 }
 
 
 
 
 
 
 private void toString(Node<E> node, StringBuilder sb, String prefix) {
 
 if (node == null)
 return;
 
 toString(node.left, sb, prefix + "L---");
 sb.append(prefix).append(node.element).append("\n");
 toString(node.right, sb, prefix + "R---");
 }
 
 
 
 
 
 @Override
 public Object root() {
 
 return root;
 }
 
 @Override
 public Object left(Object node) {
 
 return ((Node<E>)node).left;
 }
 
 @Override
 public Object right(Object node) {
 
 return ((Node<E>)node).right;
 }
 
 @Override
 public Object string(Object node) {
 
 return ((Node<E>)node).element;
 }
 
 }
 
 | 
**注:**在父类和子类都能够访问的成员变量和方法应当设置为protected类型。
(2)★实现二叉搜索树
新建一个名称为BinarySearchTree(包名为:com.atangbiji)的类,用来实现二叉搜索树;
BinarySearchTree.java文件:
| 12
 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
 
 | package com.atangbiji;
 import java.util.Comparator;
 
 @SuppressWarnings("unchecked")
 public class BinarySearchTree<E> extends BinaryTree<E>{
 
 
 private Comparator<E> comparator;
 
 
 public BinarySearchTree() {
 this(null);
 }
 
 
 public BinarySearchTree(Comparator<E> comparator) {
 this.comparator = comparator;
 }
 
 
 
 
 
 
 public void add(E element) {
 elementNotNullCheck(element);
 
 
 if (root == null) {
 root = new Node<>(element,null);
 size++;
 return;
 }
 
 
 
 Node<E> node = root;
 
 Node<E> parent = null;
 int cmp = 0;
 while (node != null) {
 
 cmp = compare(element, node.element);
 parent = node;
 
 if (cmp > 0) {
 
 node = node.right;
 }else if (cmp < 0) {
 
 node = node.left;
 }else {
 node.element = element;
 return;
 }
 }
 
 
 Node<E> newNode = new Node<>(element, parent);
 
 if (cmp > 0) {
 parent.right = newNode;
 } else if (cmp < 0) {
 parent.left = newNode;
 }
 
 
 size++;
 }
 
 
 
 
 
 
 public void remove(E element) {
 
 remove(node(element));
 }
 
 
 
 
 
 
 public boolean contains(E element) {
 
 return node(element) != null;
 }
 
 
 
 
 
 
 private void remove(Node<E> node) {
 
 if (node == null) return;
 
 size--;
 
 
 if (node.hasTwoChildren()) {
 
 Node<E> s = successor(node);
 
 node.element = s.element;
 
 node = s;
 }
 
 
 Node<E> replacement = node.left != null ? node.left : node.right;
 
 if (replacement != null) {
 
 replacement.parent = node.parent;
 
 if (node.parent == null) {
 root = replacement;
 } else if (node == node.parent.left) {
 node.parent.left = replacement;
 } else {
 node.parent.right = replacement;
 }
 } else if (node.parent == null) {
 root = null;
 } else {
 if (node == node.parent.left) {
 node.parent.left = null;
 } else {
 node.parent.right = null;
 }
 }
 }
 
 
 
 
 
 
 private Node<E> node(E element) {
 Node<E> node = root;
 while (node != null) {
 int cmp = compare(element, node.element);
 
 if (cmp == 0) return node;
 
 if (cmp > 0) {
 
 node = node.right;
 } else {
 
 node = node.left;
 }
 }
 
 return null;
 }
 
 
 
 
 
 
 private int compare(E e1,E e2) {
 
 if (comparator != null) {
 return comparator.compare(e1, e2);
 }
 
 return ((Comparable<E>)e1).compareTo(e2);
 }
 
 
 
 
 
 
 private void elementNotNullCheck(E element) {
 if (element == null) {
 throw new IllegalArgumentException("element must not null !");
 }
 }
 
 }
 
 | 
(3)自定义节点元素对象的比较逻辑
为了与之前项目二叉搜索树的功能保持一致,我们复用之前项目中自定义的节点元素对象的比较逻辑。
Person.java文件:
| 12
 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
 
 | package com.atangbiji;
 public class Person implements Comparable<Person>{
 private int age;
 private String name;
 
 
 public Person(int age, String name) {
 this.age = age;
 this.name = name;
 }
 
 
 public int getAge() {
 return age;
 }
 
 public void setAge(int age) {
 this.age = age;
 }
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 
 
 @Override
 public int compareTo(Person e) {
 
 return age - e.age;
 }
 
 @Override
 public String toString() {
 return name + "(age="+ age +")";
 }
 
 }
 
 | 
PersonComparator1.java文件:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | package com.atangbiji;
 import java.util.Comparator;
 
 public class PersonComparator1 implements Comparator<Person> {
 
 
 @Override
 public int compare(Person e1, Person e2) {
 
 return e1.getAge() - e2.getAge();
 }
 
 }
 
 | 
PersonComparator2.java文件:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | package com.atangbiji;
 import java.util.Comparator;
 
 public class PersonComparator2 implements Comparator<Person> {
 
 
 @Override
 public int compare(Person e1, Person e2) {
 
 return e2.getAge() - e1.getAge();
 }
 }
 
 | 
(4)使用小码哥MJ封装的二叉树打印接口
为了继续使用小码哥MJ封装的二叉树打印接口,我们复用小码哥MJ封装的二叉树打印工具。
(5)自定义测试类
再新建一个名称为Main(包名为:com.atangbiji)的类,用来调用(测试)自己封装的二叉搜索树。如下图所示:
 
2.2、接口测试
在Main类中新建多个BinarySearchTree对象,用来测试自己重新封装的二叉搜索树。这里仅以添加、删除、遍历节点元素等为例进行测试,其它接口的测试方法与此类似,这里不再赘述。
Main.java文件:
| 12
 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
 
 | package com.atangbiji;
 import java.util.Comparator;
 
 import com.atangbiji.BinaryTree.Visitor;
 import com.atangbiji.printer.BinaryTrees;
 
 public class Main {
 public static void main(String[] args) {
 
 
 
 
 Integer data[] = new Integer[] {
 7,4,2,1,3,5,9,8,11,10,12
 };
 
 BinarySearchTree<Integer> bst = new BinarySearchTree<>();
 
 
 for(int i = 0; i < data.length; i++){
 bst.add(data[i]);
 }
 System.out.println("一、节点元素为整数的二叉搜索树: \n");
 System.out.println("1、采用(中序)遍历法打印二叉搜索树: \n");
 System.out.println(bst);
 
 System.out.println("2、使用MJ封装的接口打印二叉搜索树: \n");
 BinaryTrees.println(bst);
 
 System.out.println("二叉树高度(递归实现)为: " + bst.height() + "\n");
 System.out.println("二叉树高度(层序遍历实现)为: " + bst.height2() + "\n");
 
 
 
 
 
 
 
 PersonComparator1 cmp1 = new PersonComparator1();
 BinarySearchTree<Person> bst1 = new BinarySearchTree<>(cmp1);
 
 bst1.add(new Person(12, "Tom"));
 bst1.add(new Person(15, "Jim"));
 bst1.add(new Person(10, "Lucy"));
 bst1.add(new Person(13, "ATang"));
 bst1.add(new Person(18, "Jan"));
 bst1.add(new Person(8, "Lily"));
 
 System.out.println("\n 二、节点元素为对象的二叉搜索树: ");
 System.out.println("\n 1、自定义比较逻辑1(Comparator接口法):假定年龄大的人所对应的节点元素大 \n");
 BinaryTrees.println(bst1);
 
 
 PersonComparator2 cmp2 = new PersonComparator2();
 BinarySearchTree<Person> bst2 = new BinarySearchTree<>(cmp2);
 
 bst2.add(new Person(12, "Tom"));
 bst2.add(new Person(15, "Jim"));
 bst2.add(new Person(15, "Jim"));
 bst2.add(new Person(10, "Lucy"));
 bst2.add(new Person(13, "ATang"));
 bst2.add(new Person(18, "Jan"));
 bst2.add(new Person(8, "Lily"));
 
 System.out.println("\n 2、自定义比较逻辑2(Comparator接口法):假定年龄大的人所对应的节点元素小 \n");
 BinaryTrees.println(bst2);
 
 
 BinarySearchTree<Person> bst3 = new BinarySearchTree<>();
 
 bst3.add(new Person(12, "Tom"));
 bst3.add(new Person(15, "Jim"));
 bst3.add(new Person(15, "Jim"));
 bst3.add(new Person(10, "Lucy"));
 bst3.add(new Person(13, "ATang"));
 bst3.add(new Person(18, "Jan"));
 bst3.add(new Person(8, "Lily"));
 
 System.out.println("\n 3、默认比较逻辑(Comparable接口法):假定年龄大的人所对应的节点元素大 \n");
 BinaryTrees.println(bst3);
 
 
 BinarySearchTree<Person> bst4 = new BinarySearchTree<>(new Comparator<Person>() {
 
 
 @Override
 public int compare(Person arg0, Person arg1) {
 
 return arg0.getAge() - arg1.getAge();
 }
 
 });
 
 bst4.add(new Person(12, "Tom"));
 bst4.add(new Person(15, "Jim"));
 bst4.add(new Person(15, "Jim"));
 bst4.add(new Person(10, "Lucy"));
 bst4.add(new Person(13, "ATang"));
 bst4.add(new Person(18, "Jan"));
 bst4.add(new Person(8, "Lily"));
 
 System.out.println("\n 4、通过匿名类自定义比较逻辑(Comparator接口法):假定年龄大的人所对应的节点元素大 \n");
 BinaryTrees.println(bst4);
 
 
 System.out.println("\n" + "\n 三、遍历二叉搜索树(全部节点): ");
 
 System.out.println("\n 使用MJ封装的接口打印二叉搜索树: \n");
 BinaryTrees.println(bst);
 
 System.out.println("\n" + "1、层序遍历二叉搜索树(全部节点):");
 bst.levelOrder(new Visitor<Integer>() {
 
 @Override
 
 public boolean visit(Integer element) {
 
 System.out.print("_" + element + "; ");
 return false;
 }
 });
 
 
 System.out.println("\n" + "2、前序遍历二叉搜索树(全部节点):");
 bst.preorder(new Visitor<Integer>() {
 
 @Override
 public boolean visit(Integer element) {
 
 System.out.print("_" + element + "; ");
 return false;
 }
 
 });
 
 System.out.println("\n" + "3、中序遍历二叉搜索树(全部节点):");
 bst.inorder(new Visitor<Integer>() {
 
 @Override
 public boolean visit(Integer element) {
 
 System.out.print("_" + element + "; ");
 return false;
 }
 
 });
 
 System.out.println("\n" + "4、后序遍历二叉搜索树(全部节点):");
 bst.postorder(new Visitor<Integer>() {
 
 @Override
 public boolean visit(Integer element) {
 
 System.out.print("_" + element + "; ");
 return false;
 }
 
 });
 
 
 System.out.println("\n" + "\n 四、遍历二叉搜索树(部分节点): ");
 
 System.out.println("\n" + "使用MJ封装的接口打印二叉搜索树: \n");
 BinaryTrees.println(bst);
 
 System.out.println("\n" + "1、层序遍历二叉搜索树(部分节点):");
 bst.levelOrder(new Visitor<Integer>() {
 
 @Override
 
 public boolean visit(Integer element) {
 
 System.out.print("_" + element + "; ");
 
 return element == 8 ? true : false;
 }
 });
 
 
 System.out.println("\n" + "2、前序遍历二叉搜索树(部分节点):");
 bst.preorder(new Visitor<Integer>() {
 
 @Override
 public boolean visit(Integer element) {
 
 System.out.print("_" + element + "; ");
 
 return element == 8 ? true : false;
 }
 
 });
 
 System.out.println("\n" + "3、中序遍历二叉搜索树(部分节点):");
 bst.inorder(new Visitor<Integer>() {
 
 @Override
 public boolean visit(Integer element) {
 
 System.out.print("_" + element + "; ");
 
 return element == 8 ? true : false;
 }
 
 });
 
 System.out.println("\n" + "4、后序遍历二叉搜索树(部分节点):");
 bst.postorder(new Visitor<Integer>() {
 
 @Override
 public boolean visit(Integer element) {
 
 System.out.print("_" + element + "; ");
 
 return element == 8 ? true : false;
 }
 
 });
 
 
 System.out.println("\n" + "\n 五、删除二叉搜索树中的元素: ");
 System.out.println("\n" + "使用MJ封装的接口打印二叉搜索树(删除前): \n");
 BinaryTrees.println(bst);
 
 
 System.out.println("\n" + "1、先删除元素值为5的叶子节点:");
 bst.remove(5);
 System.out.println("\n" + "使用MJ封装的接口打印二叉搜索树(删除元素值为5的叶子节点后): \n");
 BinaryTrees.println(bst);
 
 System.out.println("\n" + "2、在上述基础上,再删除元素值为4(度为1)的节点:");
 bst.remove(4);
 System.out.println("\n" + "使用MJ封装的接口打印二叉搜索树(再删除元素值为4(度为1)的节点后): \n");
 BinaryTrees.println(bst);
 
 System.out.println("\n" + "3、在上述基础上,再删除元素值为9(度为2)的节点:");
 bst.remove(9);
 System.out.println("\n" + "使用MJ封装的接口打印二叉搜索树(再删除元素值为9(度为2)的节点后): \n");
 BinaryTrees.println(bst);
 
 }
 }
 
 | 
运行该程序,输出结果为:






(本讲完,系列博文持续更新中…… )
参考文献:
[1] 《恋上数据结构与算法》,小码哥MJ
[2] 《数据结构与算法》,邓俊辉
如何获取源代码?
关注 “阿汤笔迹” 微信公众号,在后台回复关键词 “数据结构与算法设计与实现” ,即可获取项目源代码。

原文地址:http://www.atangbiji.com/2023/08/24/BinarySearchTree2/
博主最新文章在个人博客 http://www.atangbiji.com/ 发布。