1.递归方法
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);
}
- 层序遍历:不可以用递归,用队列
- 1.将根节点入队
2.循环执行以下操作,直到队列为空
- a.将队头节点A 出队,进行访问
b.将A的左子节点入队
c.将A的右子节点入队
如上图,7入队,7出队,将4、9入队,然后4出队,2、5入队,依此可以遍历每一层节点
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);
}
}
}
2.增强遍历接口
- 由于拿到元素并非只有打印的需求,而是对其进行操作
- 操作:定义visitor访问器接口,在上述那些前中后层次遍历的方法中将输出语句更改为由监听器内部定义的方法visitor.visit(node.element)
- 作用:可以外部自定义对元素的操作方法,并且可以输出停止位置,即输出哪个元素就停止
- 注:前中后判断停止位置的代码不同
- 定义visitor访问器接口,而接口不允许有成员变量,所以定义为抽象类:stop成员用于存储每次停止位置
public static abstract class Visitor<E> {
boolean stop;
public abstract boolean visit(E element);
}
public void preorder(Visitor<E> visitor) {
if (visitor == null) return;
preorder(root, visitor);
}
private void preorder(Node<E> node, Visitor<E> visitor) {
if (node == null || visitor.stop) return;
visitor.stop = visitor.visit(node.element);
preorder(node.left, visitor);
preorder(node.right, visitor);
}
public void inorder(Visitor<E> visitor) {
if (visitor == null) return;
inorder(root, visitor);
}
private void inorder(Node<E> node, Visitor<E> visitor) {
if (node == null || visitor.stop) return;
inorder(node.left, visitor);
if (visitor.stop) return;
visitor.stop = visitor.visit(node.element);
inorder(node.right, visitor);
}
public void postorder(Visitor<E> visitor) {
if (visitor == null) return;
postorder(root, visitor);
}
private void postorder(Node<E> node, Visitor<E> visitor) {
if (node == null || visitor.stop) return;
postorder(node.left, visitor);
postorder(node.right, visitor);
if (visitor.stop) return;
visitor.stop = 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);
}
}
}
- 测试代码:创建Visitor内部类,实现内部visit方法,默认返回false即不停止输出,所以返回true停止输出
public static void main(String[] args){
Integer data[] = new Integer[] {
7, 4, 9, 2, 1
};
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
for (int i = 0; i < data.length; i++) {
bst.add(data[i]);
}
BinaryTrees.println(bst);
bst.preorder(new BinarySearchTree.Visitor<Integer>() {
public boolean visit(Integer element) {
System.out.print(element + " ");
return element == 2 ? true : false;
}
});
}
总结:
1. if (node == null || visitor.stop) return; 的语句中的 visitor.stop 若不加,则只是输出了前几个元素,
实则还是进行了所有的递归操作,所以加上可以终止后续的递归操作,进而提高性能
2.后面的 if (visitor.stop) return; 也需要加,如在后序遍历的代码中如果不加则可能存在其右子树为true,
那么紧接着不加判断的话自己的值也会进行输出,实则不需要。因为左->右->根,右子树如果为true了,
后序不用进行输出,即根不需要输出。也就是说从打印层面看,
3.即这两句的 visitor.stop 功能是不一样的