二叉树的先序遍历顺序是根、左、右;中序遍历顺序是左、根、右;后序遍历顺序是左、右、根。
递归方式实现如下:
1 public class TreeNode {
2 private int value;
3 private TreeNode left, right;
4
5 public TreeNode(int data) {
6 value = data;
7 }
8
9 // 递归方式实现先序遍历
10 public void preorder(TreeNode treeNode) {
11 if (treeNode == null) {
12 return;
13 }
14
15 System.out.println(treeNode.value + " ");
16 preorder(treeNode.left);
17 preorder(treeNode.right);
18 }
19
20 // 递归方式实现中序遍历
21 public void inorder(TreeNode treeNode) {
22 if (treeNode == null) {
23 return;
24 }
25
26 inorder(treeNode.left);
27 System.out.println(treeNode.value + " ");
28 inorder(treeNode.right);
29 }
30
31 // 递归方式实现后序遍历
32 public void postorder(TreeNode treeNode) {
33 if (treeNode == null) {
34 return;
35 }
36
37 postorder(treeNode.left);
38 postorder(treeNode.right);
39 System.out.println(treeNode.value + " ");
40 }
41 }
递归方式能解决的问题都能用非递归方式来解决,因为递归方式通过函数栈来保存信息,普通的栈或队列也能达到相同效果。
非递归方式实现先序遍历,步骤如下:
1 如果当前结点为空,则结束。
2 创建实现了Queue接口的LinkedList对象,引用为queue。
3 当前结点入队列。
4 队头结点出队列,打印其结点值。其左右非空孩子结点入队列。
5 重复步骤4,直到queue为空。
举例:
结点1入队列,然后出队列并打印。结点2和3入队列。队列中结点(从队头到队尾,下同):2、3。
结点2出队列并打印,结点4和5入队列。队列中结点:3、4、5。
结点3出队列并打印,结点6和7入队列。队列中结点:4、5、6、7。
结点4出队列并打印。队列中结点:5、6、7。
结点5出队列并打印。队列中结点:6、7。
结点6出队列并打印。队列中结点:7。
结点7出队列并打印。
Java代码:
1 // 非递归方式实现先序遍历
2 public void preOrder(TreeNode cur) {
3 if (cur != null) {
4 Queue<TreeNode> queue = new LinkedList<TreeNode>();
5 queue.add(cur);
6
7 while (!queue.isEmpty()) {
8 cur = queue.remove();
9 System.out.println(cur.value + " ");
10
11 TreeNode left = cur.left, right = cur.right;
12 if (left != null) {
13 queue.add(left);
14 }
15 if (right != null) {
16 queue.add(right);
17 }
18 }
19 }
20 }
非递归方式实现中序遍历,步骤如下:
1 如果当前结点为空,则结束。
2 创建实现了Deque接口的LinkedList对象,引用为stack。
3 当前结点入栈,左孩子结点不断入栈,直到没有左孩子结点。
4 栈顶结点出栈,打印其结点值。如果有右孩子结点,则把它设为当前结点;否则,重复该步骤,直到有右孩子结点或者stack为空。
5 重复步骤3和4。
举例:
二叉树看上图(下同)。
结点1、2和4入栈。栈中结点(从栈顶到栈底,下同):4、2、1。
结点4和2出栈并打印,结点5入栈。栈中结点:5、1。
结点5和1出栈并打印,结点3和6入栈。栈中结点:6和3。
结点6和3出栈并打印,结点7入栈。栈中结点:7。
结点7出栈。
Java代码:
1 // 非递归方式实现中序遍历
2 public void inOrder(TreeNode cur) {
3 if (cur != null) {
4 Deque<TreeNode> stack = new LinkedList<TreeNode>();
5 while (true) {
6 // 已保证当前结点非空
7 stack.addFirst(cur);
8 for (cur = cur.left; cur != null; cur = cur.left) {
9 stack.addFirst(cur);
10 }
11
12 while (true) {
13 // 当前结点出栈并打印
14 cur = stack.removeFirst();
15 System.out.println(cur.value + " ");
16
17 TreeNode right = cur.right;
18 if (right != null) {
19 cur = right;
20 break;
21 } else if (stack.isEmpty()) {
22 return;
23 }
24 }
25 }
26 }
27 }
非递归方式实现中序遍历,步骤如下:
1 如果当前结点为空,则结束。
2 创建两个实现了Deque接口的LinkedList对象,引用为stack1和stack2。
3 当前结点入栈stack1,栈顶结点出栈。该结点入栈stack2,该结点的非空左右孩子结点入栈stack1。
4 重复步骤3,直到stack1为空。
5 stack2不断出栈并打印栈顶结点值,直到stack2为空。
举例:
结点1入栈stack1。
结点1出栈,入栈stack2。结点2和3入栈stack1。
结点3出栈,入栈stack2。结点6和7入栈stack1。
结点7出栈,入栈stack2。
结点6出栈,入栈stack2。
结点2出栈,入栈stack2。结点4和5入栈stack1。
结点5出栈,入栈stack2。
结点4出栈,入栈stack2。
结点4、5、2、6、7、3、1出栈并打印。
Java代码:
1 // 非递归方式实现后序遍历
2 public void postOrder(TreeNode cur) {
3 if (cur != null) {
4 Deque<TreeNode> stack1 = new LinkedList<TreeNode>();
5 Deque<TreeNode> stack2 = new LinkedList<TreeNode>();
6
7 stack1.addFirst(cur);
8 while (!stack1.isEmpty()) {
9 cur = stack1.removeFirst();
10 stack2.addFirst(cur);
11
12 TreeNode left = cur.left, right = cur.right;
13 if (left != null) {
14 stack1.addFirst(left);
15 }
16 if (right != null) {
17 stack1.addFirst(right);
18 }
19 }
20
21 while (!stack2.isEmpty()) {
22 System.out.println(stack2.removeFirst().value + " ");
23 }
24 }
25 }
参考资料
《程序员代码面试指南 IT名企算法与数据结构题目最优解》P88-95