本文將針對二叉樹中幾種常見的遍歷方法進行介紹。
遍歷方式
前序遍歷
前序遍歷首先訪問根節點,然後遍歷左子樹,最後遍歷右子樹。
中序遍歷
中序遍歷是先遍歷左子樹,然後訪問根節點,然後遍歷右子樹。
後序遍歷
後序遍歷是先遍歷左子樹,然後遍歷右子樹,最後訪問樹的根節點。
遞歸實現
遞歸實現二叉樹的遍歷是非常簡單的,其核心就是 深度優先搜索(DFS) 算法。
由於比較簡單,三種遍歷方式的實現代碼只是 深度優先搜索 過程中執行順序的區別,故模版如下:
public class Solution {
// 遞歸遍歷二叉樹
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> list = new ArrayList<>();
if (root == null) return list;
dfs(root, list);
return list;
}
private void dfs(TreeNode root, ArrayList<Integer> list) {
if (root == null) return;
// 前序遍歷 根 -> 左 -> 右
list.add(root.val); // 根
dfs(root.left, list); // 左
dfs(root.right, list); // 右
// 中序遍歷 右 -> 根 -> 右
// dfs(root.left, list);
// list.add(root.val);
// dfs(root.right, list);
// 後序遍歷 左 -> 右 -> 根
// dfs(node.left, list);
// dfs(node.right, list);
// list.add(node.val);
}
}
迭代實現
前序遍歷
通過迭代對前序遍歷需要一個棧進行輔助,其負責對不同層級父子節點進行迭代存儲。
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
// 1.退出最外層迭代的條件是,指針指向null,且棧爲空
while (curr != null || !stack.isEmpty()) {
// 2.內層循環按順序入棧,同時更新當前指針
// 4.這時候也可能是開始遍歷右節點
while (curr != null) {
stack.push(curr);
list.add(curr.val);
curr = curr.left;
}
// 3.返回父節點,並將指針指向右節點
curr = stack.pop();
curr = curr.right;
}
return list;
}
}
中序遍歷
中序遍歷和前序遍歷思想是一致的,區別僅僅在於根節點在左葉子節點添加之後添加:
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
// 1.退出最外層迭代的條件是,指針指向null,且棧爲空
while (!stack.isEmpty() || curr != null) {
// 2.內層循環按順序入棧,同時更新當前指針
// 5.這時候也可能是開始遍歷右節點
while (curr != null) {
stack.push(curr.left);
curr = curr.left;
}
// 3.返回父節點,並加入數組中
curr = stack.pop();
list.add(curr.val);
// 4.將指針指向右節點
curr = curr.right;
}
return list;
}
}
後序遍歷
後序遍歷 LeetCode
官方題解給出了一個額外的思路,對於樹的 後序遍歷 而言,其遍歷順序與 廣度優先搜索(BFS) 恰恰是相反的:
如圖所示,BFS
的遍歷順序是 1->2->3->4->5
,而相同的樹後序遍歷順序則是 4->5->2->3->1
。
因此,後序遍歷的思路如下:
從根節點開始依次迭代,彈出棧頂元素輸出到輸出列表中,然後依次壓入它的所有孩子節點,按照從上到下、從左至右的順序依次壓入棧中。
因爲深度優先搜索後序遍歷的順序是從下到上、從左至右,所以需要將輸出列表逆序輸出。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> output = new LinkedList<>();
// 和傳統的bfs不同,這裏並沒有用 Queue
// 因爲順序是相反的,這裏並不是取第一個元素,而是取棧頂的元素(即同層級節點從右->左遍歷)
Stack<TreeNode> stack = new Stack<>();
if (root == null) return output;
stack.push(root);
while(!stack.isEmpty()) {
TreeNode node = stack.pop();
output.addFirst(node.val);
if (node.left != null) {
stack.push(node.left);
}
if (node.right != null) {
stack.push(node.right);
}
}
return output;
}
}
參考 & 感謝
文章絕大部分內容節選自LeetCode
,概述:
- https://leetcode-cn.com/explore/learn/card/data-structure-binary-tree/2/traverse-a-tree/7/
例題:
- https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
- https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
- https://leetcode-cn.com/problems/binary-tree-postorder-traversal/
關於我
Hello,我是 卻把清梅嗅 ,如果您覺得文章對您有價值,歡迎 ❤️,也歡迎關注我的 博客 或者 GitHub。
如果您覺得文章還差了那麼點東西,也請通過關注督促我寫出更好的文章——萬一哪天我進步了呢?