二叉樹的先,中,后序遍歷(遞歸,非遞歸)
作者:Grey
原文地址:
說明
本文主要介紹了二叉樹的先序,中序,后序遍歷。並且分別用如下兩種方式實現:
- 遞歸方法
- 非遞歸(使用棧)
示例二叉樹
數據結構
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
先序遍歷
先序遍歷流程
先頭,再左,再右。
示例中的二叉樹,先序遍歷的結果為:
1-->2-->4-->7-->11-->8-->12-->3-->5-->6-->9-->13-->10
遞歸方法實現先序遍歷
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
if (root == null) {
return new ArrayList<>();
}
List<Integer> ans = new ArrayList<>();
pre(root, ans);
return ans;
}
private void pre(TreeNode root, List<Integer> ans) {
if (root == null) {
return;
}
ans.add(root.val);
pre(root.left, ans);
pre(root.right, ans);
}
}
使用棧實現先序遍歷
整個流程是分如下幾個步驟:
第一步,申請一個棧,並把頭節點壓入。
第二步,彈出就收集答案。
第三步,第二步中彈出的節點,如果右孩子不為空,則右孩子入棧。
第四步,第二步中彈出的節點,如果左孩子不為空,則左孩子入棧。
第五步,循環執行第二步到第四步,直到棧為空。
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
if (null == root) {
return new ArrayList<>();
}
List<Integer> ans = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
ans.add(node.val);
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
return ans;
}
}
測評鏈接:LeetCode 144. Binary Tree Preorder Traversal
中序遍歷
中序遍歷流程
先中,再左,再右。
示例中的二叉樹,中序遍歷的結果為:
2-->11-->7-->4-->12-->8-->1-->5-->3-->9-->13-->6-->10
遞歸方法實現中序遍歷
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
if (root == null) {
return new ArrayList<>();
}
List<Integer> ans = new ArrayList<>();
in(root, ans);
return ans;
}
private void in(TreeNode root, List<Integer> ans) {
if (root == null) {
return;
}
in(root.left, ans);
ans.add(root.val);
in(root.right, ans);
}
}
使用棧實現中序遍歷
也是申請一個棧,有如下幾個步驟:
第一步,整條左邊界入棧。
第二步,彈出就收集答案。
第三步,來到右樹上執行同第一步的操作。
第四步,直到棧為空。
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
if (root == null) {
return new ArrayList<>();
}
List<Integer> ans = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode cur = root;
while (!stack.isEmpty() || cur != null) {
if (cur != null) {
// 整條左邊界入棧
stack.push(cur);
cur = cur.left;
} else {
TreeNode node = stack.pop();
// 彈出收集答案
ans.add(node.val);
// 來到右樹上做同樣的操作
cur = node.right;
}
}
return ans;
}
}
測評鏈接:LeetCode 94. Binary Tree Inorder Traversal
后序遍歷
后序遍歷流程
先左,后右,再中。
示例中的二叉樹,后序遍歷的結果為:
11-->7-->12-->8-->4-->2-->5-->13-->9-->10-->6-->3-->1
遞歸方法實現后序遍歷
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
if (root == null) {
return new ArrayList<>();
}
List<Integer> ans = new ArrayList<>();
post(root, ans);
return ans;
}
public void post(TreeNode root, List<Integer> ans) {
if (root == null) {
return;
}
post(root.left, ans);
post(root.right, ans);
ans.add(root.val);
}
}
使用兩個棧實現后序遍歷
由於我們已經可以通過棧來實現先序遍歷,即:先頭,再左,再右。
而后序遍歷的流程是:先左,再右,再頭。
所以我們可以通過先序遍歷的代碼簡單加工得到后序遍歷的代碼。
首先,我們先通過先序遍歷的代碼,將先序遍歷加工成:先頭,再右,再左。
把這個結果放入一個棧中,假設這個棧叫helper
, 然后將helper
中的內容依次彈出,便是后序遍歷的結果。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
if (root == null) {
return new ArrayList<>();
}
List<Integer> ans = new ArrayList<>();
Deque<TreeNode> helper = new ArrayDeque<>();
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode cur = root;
stack.push(cur);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
helper.push(node);
// 先序遍歷的時候,是先判斷右樹,改造一下,先判斷左樹
if (node.left != null) {
cur = node.left;
stack.push(cur);
}
if (node.right != null) {
cur = node.right;
stack.push(cur);
}
}
while (!helper.isEmpty()) {
ans.add(helper.pop().val);
}
return ans;
}
}
測評鏈接:LeetCode 145. Binary Tree Postorder Traversal