1. 程式人生 > 實用技巧 >【總結】二叉樹的前中後序遍歷(遞迴和非遞迴)

【總結】二叉樹的前中後序遍歷(遞迴和非遞迴)

一、前中後序遞迴

1. 前序遞迴( 時間複雜度O(n)、空間複雜度O(n))

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        dfs(root, res);
        return res;
    }
    private void dfs(TreeNode root, List<Integer> res) {
        
if (root == null) return; res.add(root.val); // dfs(root.left, res); // dfs(root.right, res); // } }

2. 中序遞迴( 時間複雜度O(n)、空間複雜度O(n))

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        dfs(root,res);
        
return res; } private void dfs(TreeNode root, List<Integer> res) { if (root == null) return; dfs(root.left, res); // res.add(root.val); // dfs(root.right, res); // } }

3. 後序遞迴( 時間複雜度O(n)、空間複雜度O(n))

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List
<Integer> res = new ArrayList<>(); dfs(root, res); return res; } private void dfs(TreeNode root, List<Integer> res) { if (root == null) return; dfs(root.left, res); // dfs(root.right, res);// res.add(root.val);// } }

二、前中後序非遞迴

  前中後序遍歷都屬於深度遍歷,所以需要使用棧。層次遍歷需要用到佇列。

1. 前序非遞迴(時間複雜度O(n)、空間複雜度O(n))

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                res.add(root.val);
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            root = root.right;
        }
        return res;
    }
}

2. 中序非遞迴( 時間複雜度O(n)、空間複雜度O(n))

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            res.add(root.val);
            root = root.right;
        }
        return res;
    }
}

3.後序非遞迴( 時間複雜度O(n)、空間複雜度O(n))

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode pre = null; //pre節點用於記錄前一次訪問的節點
        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.peek();
            // 若右節點為空 或右節點訪問過
            if (root.right == null || root.right == pre) {
                res.add(root.val); //此時可以訪問根結點啦
                stack.pop();
                pre = root;
                root = null; //此時下一輪迴圈不要將左子樹壓棧,直接判斷棧頂元素
            }else {
                root = root.right; //先不出棧 把它右節點入棧
            }
        }
        return res;
    }
}

後序非遞迴的另一種寫法,修改前序【根左右】的遍歷順序為【根右左】,前序遍歷是往後加元素,後序遍歷是往前加元素

class Solution {
    //修改前序遍歷,每次先檢視右節點再檢視左節點。同時,節點寫入結果將插入隊尾修改為插入隊首
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                res.add(0,root.val);  // 取根節點的值,插入list最後邊
                stack.push(root);
                root = root.right; // 遍歷右子樹
            }
            root = stack.pop();
            root = root.left; // 遍歷左子樹
        }
        return res;
    }
}

三、層序遍歷

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> queue = new LinkedList<>(); // 層序需要藉助佇列
        queue.offer(root);
        while (!queue.isEmpty()) {
            int level = queue.size();
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < level; i++) {
                TreeNode cur = queue.poll();
                list.add(cur.val);
                if (cur.left != null) queue.offer(cur.left);
                if (cur.right != null) queue.offer(cur.right);
            }
            res.add(list);
        }
        return res;
    }
}

四、相關習題

LeetCode144. 二叉樹的前序遍歷LeetCode94. 二叉樹的中序遍歷LeetCode145. 二叉樹的後序遍歷、LeetCode102. 二叉樹的層序遍歷

參考:

  二叉樹層序遍歷問題總結

  二叉樹 前序+中序+後序+層序遍歷(遞迴+迭代)