算法训练营第十四天|二叉树的递归遍历、迭代遍历、统一迭代

90 阅读1分钟

144. 二叉树的前序遍历

递归遍历:

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

迭代遍历:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        Stack<TreeNode> stk = new Stack<>();
        List<Integer> res = new ArrayList<>();

        if(root == null){
            return res;
        }
        stk.push(root);
        while(!stk.isEmpty()){
            // 每次都是先处理“中”,前序遍历顺序为中-左-右,所以压入栈的顺序要中-右-左,然后中先被处理,然后按左-右的顺序出栈
            TreeNode node = stk.pop();
            res.add(node.val);
            if(node.right != null)stk.push(node.right);
            if(node.left != null)stk.push(node.left);
        }
        return res;
    }
}

94. 二叉树的中序遍历

递归遍历:

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

迭代遍历:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        Stack<TreeNode> stk = new Stack<>();
        List<Integer> res = new ArrayList<>();
        if(root == null)return res;

        while(root != null || !stk.isEmpty()){
            if(root != null){
                stk.push(root);
                root = root.left;
            }
            else{
                root = stk.pop();
                res.add(root.val);
                root = root.right;
            }
        }

        return res;
    }
}

145. 二叉树的后序遍历

递归遍历:

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

迭代遍历:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        // 后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左,最后翻转结果
        Stack<TreeNode> stk = new Stack<>();
        List<Integer> res = new ArrayList<>();
        if(root == null){
            return res;
        }
        stk.push(root);
        while(!stk.isEmpty()){
            TreeNode node = stk.pop();
            res.add(node.val);
            if(node.left != null)stk.push(node.left);
            if(node.right != null)stk.push(node.right);
        }
        Collections.reverse(res); // Collections.reverse()对列表进行原地修改并且返回void
        return res;
    }
}

迭代的统一写法

以中序遍历为例

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<Integer> stack = new Stack<>();
        if(root != null)stack.push(root); // 先压入根节点
        
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node != null){
                stack.pop(); // 先将该节点弹出避免重复操作

                // 以下就是核心部分
                // 中序遍历顺序是左根右,所以压栈就是右根左
                if(node.right != null)stack.push(node.right);
                stack.push(node);
                stack.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
                if(node.left != null)stack.push(node.left);
            }
            else {// 只有遇到空节点的时候,才将下一个节点放进结果集
                stack.pop(); // 弹出空节点
                node = stack.pop(); // 重新取出栈中元素
                res.add(node.val);
            }
        }
        
        return res;
    }
}

将上述代码适用于不同的遍历顺序时,只需要按照相应的顺序压栈即可。