二叉搜索树及 Java 实现
定义
由一棵二叉树构成,满足:
$$
left.key<key<=right.key
$$
进一步有:
$$
key<=right.key<parent.key
$$
大部分二叉搜索树的最坏运行时间与树的高度成正比
| 12
 3
 4
 5
 
 | Tree parent;
 Tree left;
 Tree right;
 var key;
 
 | 
遍历方法
 1.中序遍历:
  通过递归方法,先找出左节点,再找出当前节点,最后是右节点。
  定理:若树节点为n,则调用该遍历方法需要O(n)的时间。
 2.先序遍历
  先当前节点,后左节点,最后右节点。
 3.后序遍历
  先左节点,后右节点,最后当前节点。
| 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
 
 | public void inorder() {
 inorder(this);
 }
 private void inorder(Tree node) {
 if (node.left != null) inorder(node.left);
 System.out.println(node.key);
 if (node.right != null) inorder(node.right);
 }
 
 
 public void preorder() {
 preorder(this);
 }
 private void preorder(Tree node) {
 System.out.println(node.key);
 if (node.left != null) preorder(node.left);
 if (node.right != null) preorder(node.right);
 }
 
 
 public void postorder() {
 postorder(this);
 }
 private void postorder(Tree node) {
 System.out.println(node.key);
 if (node.left != null) postorder(node.left);
 if (node.right != null) postorder(node.right);
 }
 
 | 
查找
给定一关键字key,返回第一个找到的含该关键字的树节点,没有则返回null。
运行时间为O(h),h为树的高度。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | public Tree search(int key) {
 if (key == this.key) return this;
 if (key < this.key) return left != null ? left.search(key) : null;
 return right != null ? right.search(key) : null;
 }
 
 
 public Tree iterativeSearch(int key) {
 Tree root = new Tree();
 root = this;
 while (root != null && root.key != key) {
 if (key < this.key) root = root.left != null ? root.left : null;
 else root = root.right != null ? root.right : null;
 }
 return root;
 }
 
 | 
最大值和最小值:仅需查找左/右节点到头即可,运行时间为O(h)。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | public Tree minimum(Tree node) {
 if (node.left == null) return node;
 else return minimum(node.left);
 }
 
 
 public Tree iterativeMinimum(Tree node) {
 while (node.left != null) node = node.left;
 return node;
 }
 
 
 public Tree maximum(Tree node) {
 if (node.right == null) return node;
 else return maximum(node.right);
 }
 
 
 public Tree iterativeMaximum(Tree node) {
 while (node.right != null) node = node.right;
 return node;
 }
 
 | 
后继和前驱:关键字key的最小大于值和最大小于值(key均不相等的情况下),运行时间为O(h)。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | public Tree predecessor(Tree node) {
 if (node.left != null) return maximum(node.left);
 Tree node_p = node.parent;
 while (node_p != null && node == node_p.left) {
 node = node_p;
 node_p = node_p.parent;
 }
 return node_p;
 }
 
 
 public Tree successor(Tree node) {
 if (node.right != null) return maximum(node.right);
 Tree node_p = node.parent;
 while (node_p != null && node == node_p.right) {
 node = node_p;
 node_p = node_p.parent;
 }
 return node_p;
 }
 
 | 
插入和删除
插入和删除会引发树结构的动态集合的变化。插入相对简单,但删除较为复杂。
插入:从根节点向下遍历到指定位置,实际上为新叶子节点的添加。
| 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
 
 | public void insert(int key) {
 if (key < this.key) {
 if (left == null) {
 left = new Tree();
 left.key = key;
 left.parent = this;
 } else left.insert(key);
 } else {
 if (right == null) {
 right = new Tree();
 right.key = key;
 right.parent = this;
 } else right.insert(key);
 }
 }
 
 
 public void iterativeInsert(int key) {
 Tree parent = null;
 Tree x = this;
 while (x != null) {
 parent = x;
 if (key < x.key) x = x.left;
 else x = x.right;
 }
 if (key < parent.key) {
 parent.left = new Tree();
 parent.left.key = key;
 parent.left.parent = parent;
 } else {
 parent.right = new Tree();
 parent.right.key = key;
 parent.right.parent = parent;
 }
 }
 
 | 
删除:有三种情况,有一种较为棘手,设该节点为z。
- z节点没有子节点,则仅将对应父节点连接的子节点位置修改为- null;
- z节点有一个子节点,则将该子节点与父节点相连;
- z节点有两个子节点,则应寻找其后继- y,将- y代替- z,- z的子节点和父节点改接到- y上,并将原- y的父节点连接的子节点位置修改为- null。该情况较为棘手,还涉及- y是否为- z右子节点的情况。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | public void delete(Tree node) {
 
 if (node.left == null) transPlant(node, node.right, false);
 
 else if (node.right == null) transPlant(node, node.left, true);
 
 else {
 Tree next = successor(node);
 
 if (next != node.right) {
 transPlant(next, next.right, false);
 next.right = node.right;
 }
 
 transPlant(node, next, false);
 }
 }
 
 private void transPlant(Tree node, Tree next, boolean isLeft) {
 if (isLeft) next.right = node.right;
 else next.left = node.left;
 if (node == node.parent.left) node.parent.left = next;
 else node.parent.right = next;
 }
 
 |