一、预备知识
首先你得了解 树 的基本概念,二叉树是每个结点至多只有两个子结点的树,常称之为左右结点。
二叉树的遍历方式有 先序遍历(preorder traeversal)、中序遍历(inorder traversal)、后序遍历(postorder traversal) 三种,假设结点为 N,左子结点为 L,右子结点为 R。则:
- 先序遍历:NLR(N 在最前面)
- 中序遍历:LNR(N 在中间)
- 后序遍历:LRN(N 在最后面)
二、二叉树举例
针对以上这个二叉树,3 种遍历结果为:
先序遍历:0 1 3 7 8 4 9 2 5 6
中序遍历:7 3 8 1 9 4 0 5 2 6
后序遍历:7 8 3 9 4 1 5 6 2 0
三、递归实现方式
使用递归是很容易实现二叉树的遍历的。以下是代码示例:
public class Main {
public static void main(String[] args) {
TreeNode root = getTestTree(); // 初始化一个二叉树
preorderTraversal(root); // 先序遍历
System.out.println();
inorderTraversal(root); // 中序遍历
System.out.println();
postorderTraversal(root); // 后序遍历
}
public static void preorderTraversal(TreeNode root) {
if (root == null) return;
System.out.print(root.getData() + " ");
preorderTraversal(root.getLeft());
preorderTraversal(root.getRight());
}
public static void inorderTraversal(TreeNode root) {
if (root == null) return;
inorderTraversal(root.getLeft());
System.out.print(root.getData() + " ");
inorderTraversal(root.getRight());
}
public static void postorderTraversal(TreeNode root) {
if (root == null) return;
postorderTraversal(root.getLeft());
postorderTraversal(root.getRight());
System.out.print(root.getData() + " ");
}
public static TreeNode getTestTree() {
TreeNode[] nodes = new TreeNode[10];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new TreeNode(i);
}
nodes[0].setLeft(nodes[1]);
nodes[0].setRight(nodes[2]);
nodes[1].setLeft(nodes[3]);
nodes[1].setRight(nodes[4]);
nodes[2].setLeft(nodes[5]);
nodes[2].setRight(nodes[6]);
nodes[3].setLeft(nodes[7]);
nodes[3].setRight(nodes[8]);
nodes[4].setLeft(nodes[9]);
return nodes[0];
}
}
当然,还有一个很简单的 TreeNode 类,如下:
public class TreeNode {
private int data;
private TreeNode left;
private TreeNode right;
public TreeNode(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public TreeNode getLeft() {
return left;
}
public void setLeft(TreeNode left) {
this.left = left;
}
public TreeNode getRight() {
return right;
}
public void setRight(TreeNode right) {
this.right = right;
}
}
执行结果:
0 1 3 7 8 4 9 2 5 6
7 3 8 1 9 4 0 5 2 6
7 8 3 9 4 1 5 6 2 0
四、循环实现方式
不使用递归,而使用循环的方式变量二叉树,这是一个比较常见的面试题,实现起来也不会太难。
我们需要用到一个 栈 来帮助我们存储一些结点信息。以下是代码示例:
import java.util.Stack;
public class Main {
public static void main(String[] args) {
TreeNode root = getTestTree(); // 初始化一个二叉树
preorderTraversal(root); // 先序遍历
System.out.println();
inorderTraversal(root); // 中序遍历
System.out.println();
postorderTraversal(root); // 后序遍历
}
public static void preorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode current = root;
while (current != null || !stack.isEmpty()) {
if (current != null) {
System.out.print(current.getData() + " ");
stack.push(current);
current = current.getLeft();
} else {
current = stack.pop().getRight();
}
}
}
public static void inorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode current = root;
while (current != null || !stack.isEmpty()) {
if (current != null) {
stack.push(current);
current = current.getLeft();
} else {
current = stack.pop();
System.out.print(current.getData() + " ");
current = current.getRight();
}
}
}
public static void postorderTraversal(TreeNode root) {
if (root == null) return;
Stack<TreeNode> stack = new Stack<>();
TreeNode current = root;
stack.push(current);
stack.push(current); // 每个结点 push 两次,这样可以简单的判断出哪些结点是否处理过
while (!stack.isEmpty()) {
current = stack.pop();
if (!stack.isEmpty() && current == stack.peek()) {
if (current.getRight() != null) {
stack.push(current.getRight());
stack.push(current.getRight());
}
if (current.getLeft() != null) {
stack.push(current.getLeft());
stack.push(current.getLeft());
}
} else {
System.out.print(current.getData() + " ");
}
}
}
public static TreeNode getTestTree() {
TreeNode[] nodes = new TreeNode[10];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new TreeNode(i);
}
nodes[0].setLeft(nodes[1]);
nodes[0].setRight(nodes[2]);
nodes[1].setLeft(nodes[3]);
nodes[1].setRight(nodes[4]);
nodes[2].setLeft(nodes[5]);
nodes[2].setRight(nodes[6]);
nodes[3].setLeft(nodes[7]);
nodes[3].setRight(nodes[8]);
nodes[4].setLeft(nodes[9]);
return nodes[0];
}
}
TreeNode 类同上,不再重复贴出,执行结果:
0 1 3 7 8 4 9 2 5 6
7 3 8 1 9 4 0 5 2 6
7 8 3 9 4 1 5 6 2 0