Day 13 二叉樹part01

12点不睡觉还想干啥?發表於2024-07-15

Day 13 二叉樹part01

二叉樹的遞迴遍歷

這個用遞迴就好,現在寫起來基本沒問題

二叉樹的迭代遍歷

這個是重點,今天寫的時候居然一次寫出來了,多刷還是有用的。前中後三種遍歷方式,其迭代版本的難度排序 前 < 中 < 後。所以寫的時候也是按這個順序去做的。

144. 二叉樹的前序遍歷

使用一個棧來儲存需要遍歷的節點,注意,當遍歷一個節點後,我們需要先將其右節點壓棧再壓棧左節點,這樣可以保證先遍歷左子樹再右子樹。

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

94. 二叉樹的中序遍歷

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if(root == null) return res;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()){   //cur代表要遍歷的節點
            while(cur != null){  //一直向左走,一直到null
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();  //此時從棧中彈出的節點一定是最左的,因此可以遍歷它了
            res.add(cur.val);
            cur = cur.right;  //當該節點遍歷完,就應該去遍歷其右子樹
        }
        return res;
    }
}

145. 二叉樹的後序遍歷

與中序遍歷非常相似,一定要比較著學。

與中序的不同之處在於:

  • 中序遍歷中,從棧中彈出的節點,其左子樹是訪問完了,可以直接訪問該節點,然後接下來訪問右子樹。
  • 後序遍歷中,從棧中彈出的節點,我們只能確定其左子樹肯定訪問完了,但是無法確定右子樹是否訪問過。

因此,我們在後序遍歷中,引入了一個pre來記錄歷史訪問記錄。

  • 當訪問完一棵子樹的時候,我們用pre指向該節點。
  • 這樣,在回溯到父節點的時候,我們可以依據pre是指向左子節點,還是右子節點,來判斷父節點的訪問情況。

while(!stack.isEmpty() || cur != null)對於中序遍歷和後序遍歷判斷條件的理解:

  • 對於左子樹訪問和右子樹訪問是不同的,當訪問一個節點的時候,我們會從該節點開始,壓棧並一直向左走,直到沒有左子樹才去彈棧,然後轉向去訪問右子樹
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root, pre = null;
        while(cur != null || !stack.isEmpty()){
            while(cur != null){ //和中序遍歷完全一致,走到最左即可
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            if(cur.right == null || cur.right == pre) { 
                //如果一個節點沒有右子樹,或者右子樹已經遍歷過,那麼這個節點就可以被訪問了
                res.add(cur.val);
                pre = cur;
                cur = null;
            }else{ //右子樹還沒遍歷,先將cur還原回棧中,轉而遍歷右子樹
                stack.push(cur);
                cur = cur.right;
            }
            
        }
        return res;
    }
}

相關文章