數據結構 遞歸和非遞歸方式實現二叉樹先序、中序和後序遍歷
二叉樹的先序遍歷順序是根、左、右;中序遍歷順序是左、根、右;後序遍歷順序是左、右、根。
遞歸方式實現如下:
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
數據結構 遞歸和非遞歸方式實現二叉樹先序、中序和後序遍歷