二叉搜索树(binary search tree),它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。每个节点所形成的子树都满足该性质。
public class BST01<E extends Comparable<E>> {
private class Node {
E e;
Node left; //左子节点
Node right; //右子节点
public Node(E e) {
this.e = e;
}
}
}
先定义一个根节点属性 Node root;
public void add(E e) {
root = add(root, e);
}
private Node add(Node node, E e) {
if (node == null) {
return new Node(e);
}
if (e.compareTo(node.e) > 0) {
node.right = add(node.right, e);
} else /*if (e.compareTo(node.e) < 0)*/ {
node.left = add(node.left, e);
}
return node;
}
上面的 else 实现,包含了 <= 的节点;若把注释打开,则不含 = 的节点。
public void addByCircle(E e) {
if (root == null) {
root = new Node(e);
} else {
Node p = root;
while (p != null) {
if (e.compareTo(p.e) > 0) {
if (p.right == null) {
p.right = new Node(e);
break;
} else {
p = p.right;
}
} else /*if (e.compareTo(p.e) < 0)*/ {
if (p.left == null) {
p.left = new Node(e);
break;
} else {
p = p.left;
}
} /*else {
break;
}*/
}
}
}
上面的 else 实现,包含了 <= 的节点;若把两处注释打开,则不含 = 的节点。
打印出树中所有节点的元素 e 的值,并且按照层级顺序进行打印。
public void levelOrder1() {
Queue<Node> queue = new LinkedList<>();
queue.add(root);
StringBuilder sb = new StringBuilder();
while (!queue.isEmpty()) {
Node node = queue.remove();
sb.append(node.e + " ");
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
System.out.println(sb);
}
从 root 开始,每取出一个节点,都将它的左右子节点存到一个先进先出的队列中。
public static void main(String[] args) {
BST01<Integer> bst = new BST01<>();
bst.add(33);
bst.add(31);
bst.add(36);
bst.add(19);
bst.add(92);
bst.add(9);
bst.add(38);
bst.add(98);
bst.add(43);
bst.add(54);
bst.add(54);
bst.add(98);
bst.add(19);
bst.levelOrder1();
}
输出
33 31 36 19 92 9 38 98 19 43 98 54 54
由上面的输出,来看层级结构,还不是很清晰。
下面对 Node
增加一个 表示 层级深度的属性 depth
private class Node {
E e;
Node left;
Node right;
int depth;
public Node(E e) {
this.e = e;
}
public Node(E e, int depth) {
this(e);
this.depth = depth;
}
}
相应的,要修改添加节点和遍历方法。
最终如下
public class BST01<E extends Comparable<E>> {
private class Node {
E e;
Node left;
Node right;
int depth;
public Node(E e) {
this.e = e;
}
public Node(E e, int depth) {
this(e);
this.depth = depth;
}
}
private Node root;
public void add(E e) {
root = add(root, e, 0);
}
private Node add(Node node, E e, int depth) {
if (node == null) {
return new Node(e, depth);
}
if (e.compareTo(node.e) > 0) {
node.right = add(node.right, e, depth + 1);
} else /*if (e.compareTo(node.e) <= 0)*/ {
node.left = add(node.left, e, depth + 1);
}
return node;
}
public void addByCircle(E e) {
if (root == null) {
root = new Node(e);
root.depth = 0;
} else {
Node p = root;
while (p != null) {
if (e.compareTo(p.e) > 0) {
if (p.right == null) {
p.right = new Node(e, p.depth + 1);
break;
} else {
p = p.right;
}
} else /*if (e.compareTo(p.e) < 0)*/ {
if (p.left == null) {
p.left = new Node(e, p.depth + 1);
break;
} else {
p = p.left;
}
} /*else {
break;
}*/
}
}
}
public void levelOrder1() {
Queue<Node> queue = new LinkedList<>();
queue.add(root);
StringBuilder sb = new StringBuilder();
while (!queue.isEmpty()) {
Node node = queue.remove();
sb.append(node.e + " ");
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
System.out.println(sb);
}
public void levelOrder2() {
Queue<Node> queue = new LinkedList<>();
queue.add(root);
StringBuilder sb = new StringBuilder();
int tempDepth = -1;
while (!queue.isEmpty()) {
Node node = queue.remove();
if (tempDepth != node.depth) {
sb.append("\n");
}
sb.append(node.e + "(depth=" + node.depth +") ");
tempDepth = node.depth;
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
System.out.println(sb);
}
}
添加同样的测试数据,然后调用 levelOrder2()
遍历。
输出
33(depth=0)
31(depth=1) 36(depth=1)
19(depth=2) 92(depth=2)
9(depth=3) 38(depth=3) 98(depth=3)
19(depth=4) 43(depth=4) 98(depth=4)
54(depth=5)
54(depth=6)
这样的输出结构,来了解这个二叉搜索树更直观。
整个树应该是这样的
33
31 36
19 92
9 38 98
19 43 98
54
54