[豪の算法奇妙冒险] 代码随想录算法训练营第十三天 | 递归遍历、迭代遍历、统一迭代、层序遍历

代码随想录算法训练营第十三天 | 递归遍历、迭代遍历、统一迭代、层序遍历


递归遍历

文章讲解:https://programmercarl.com/二叉树的递归遍历.html

视频讲解:https://www.bilibili.com/video/BV1Wh411S7xt/?vd_source=b989f2b109eb3b17e8178154a7de7a51

递归算法三要素

  • 确定递归函数的参数和返回值:确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数,并且还要明确每次递归的返回值是什么,进而确定递归函数的返回类型
  • 确定终止条件:写完递归算法,运行的时候,经常会遇到栈溢出的错误,其实就是没写终止条件或者终止条件写的不对。操作系统是用一个栈的结构来保存每一层递归的信息,如果递归没有正确终止,操作系统的内存栈必然就会溢出
  • 确定单层递归的逻辑:确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程

LeetCode144 二叉树的前序遍历

题目链接:https://leetcode.cn/problems/binary-tree-preorder-traversal/description/

image-20251202171142175

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        preOrder(result, root);
        return result;
    }

    public void preOrder(List<Integer> result, TreeNode root){
        if(root == null){
            return;
        }
        result.add(root.val);
        preOrder(result, root.left);
        preOrder(result, root.right);
    }
}

LeetCode145 二叉树的后序遍历

题目链接:https://leetcode.cn/problems/binary-tree-postorder-traversal/description/

image-20251202171504615

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        postOrder(result, root);
        return result;
    }

    public void postOrder(List<Integer> result, TreeNode root){
        if(root == null){
            return;
        }
        postOrder(result, root.left);
        postOrder(result, root.right);
        result.add(root.val);
    }
}

LeetCode94 二叉树的中序遍历

题目链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/description/

image-20251202171758764

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        inOrder(result, root);
        return result;
    }

    public void inOrder(List<Integer> result, TreeNode root){
        if(root == null){
            return;
        }
        inOrder(result, root.left);
        result.add(root.val);
        inOrder(result,root.right);
    }
}

迭代遍历

文章讲解:https://programmercarl.com/二叉树的迭代遍历.html

视频讲解:

LeetCode 144 二叉树的前序遍历

题目链接:https://leetcode.cn/problems/binary-tree-preorder-traversal/

​ 用栈来模拟递归过程,即可以使用 循环+栈 来替代递归法

​ 前序遍历是根左右,但因为栈是先进后出,所以处理完根节点以后,先将非空右节点入栈,再将非空左节点入栈,这样出栈的时候就能保持根左右的顺序

image-20251202192310003

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        preOrder(result, root);
        return result;
    }

    public void preOrder(List<Integer> result, TreeNode root){
        Stack<TreeNode> stack = new Stack<>();
        if(root == null){
            return;
        }
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode cur = stack.pop();
            result.add(cur.val);
            if(cur.right != null){
                stack.push(cur.right);
            }
            if(cur.left != null){
                stack.push(cur.left);
            }
        }
    }
}

LeetCode145 二叉树的后序遍历

题目链接:https://leetcode.cn/problems/binary-tree-postorder-traversal/description/

​ 前序遍历是根左右,因为栈是先进后出,所以入栈的顺序是根右左,那么如果按根左右的顺序入栈,得到的遍历顺序是根右左,再将其反转就能得到左右根,即后序遍历顺序

image-20251202193748221

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        postOrder(result, root);
        return result;
    }

    public void postOrder(List<Integer> result, TreeNode root){
        Stack<TreeNode> stack = new Stack<>();
        if(root == null){
            return;
        }
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode cur = stack.pop();
            result.add(cur.val);
            if(cur.left != null){
                stack.push(cur.left);
            }
            if(cur.right != null){
                stack.push(cur.right);
            }
        }
        Collections.reverse(result);
    }
}

LeetCode94 二叉树的中序遍历

题目链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/description/

​ 中序遍历是左根右,先访问的是二叉树顶部节点,然后一层一层向下访问,直到到达树左面的最底部再开始处理节点,即处理顺序与访问顺序不一致

​ 故在使用迭代法写中序遍历二叉树时,需要使用指针的遍历来帮助访问节点,栈则用来记录遍历的元素及处理节点元素

image-20251202200213565

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        inOrder(result, root);
        return result;
    }

    public void inOrder(List<Integer> result, TreeNode root){
        if(root == null){
            return;
        }
        TreeNode cur = root;
        Stack<TreeNode> stack = new Stack<>();
        while(cur != null || !stack.isEmpty()){
            if(cur != null){
                stack.push(cur);
                cur = cur.left;
            }else{
                cur = stack.pop();
                result.add(cur.val);
                cur = cur.right;
            }
        }
    }
}

统一迭代

文章链接:https://programmercarl.com/二叉树的统一迭代法.html

​ 使用栈的话,无法同时解决访问节点(遍历节点)和处理节点(将元素放入结果集)不一致的情况,那我们就将访问的节点放入栈中,把要处理的节点也放入栈中,但是要额外打标记

​ 如何打标记?使用空指针标记法,在要处理的节点放入栈后,紧接着放入一个空指针作为标记

​ 以中序遍历为例,遍历到当前节点不为空,弹出该节点,再将非空右节点压入栈,再将中节点压入栈,中节点访问过但没处理,故再压入空节点做标记,之后再压入非空左节点

​ 当遍历到当前节点为空节点时,先将空节点弹出,再弹出下一个元素,此元素即可加入结果集

image-20251202202503787

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Stack<TreeNode> stack = new Stack();
        if(root != null){
            stack.push(root);
        }
        while(!stack.isEmpty()){
            TreeNode cur = stack.peek();
            if(cur != null){
                stack.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中(中序遍历-左中右,入栈顺序右中左)
                if(cur.right != null){
                    stack.push(cur.right);
                }
                stack.push(cur);
                stack.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记
                if(cur.left != null){
                    stack.push(cur.left);
                }
            }else{ // 只有遇到空节点的时候,才将下一个节点放进结果集
                stack.pop();
                result.add(stack.pop().val);
            }
        }
        return result;
    }
}

层序遍历

文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html

视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2/?vd_source=b989f2b109eb3b17e8178154a7de7a51

LeetCode102 二叉树的层序遍历

题目链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/description/

image-20251202205822782

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if(root == null){
            return result;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        while(!queue.isEmpty()){
            List<Integer> curLevel = new ArrayList<>();
            int size = queue.size();
            while(size > 0){
                TreeNode curNode = queue.poll();
                curLevel.add(curNode.val);

                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }

                size--;
            }
            result.add(curLevel);
        }
        return result;
    }
}

LeetCode107 二叉树的层序遍历Ⅱ

题目链接:https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/description/

image-20251202210633361

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> records = new ArrayList<>();
        if(root == null){
            return records;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            List<Integer> curLevel = new ArrayList<>();
            while(size > 0){
                TreeNode curNode = queue.poll();
                curLevel.add(curNode.val);

                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }
                size--;
            }
            records.add(curLevel);
        }

        List<List<Integer>> result = new ArrayList<>();
        for(int i = records.size()-1; i >= 0; i--){
            result.add(records.get(i));
        }
        return result;
    }
}

LeetCode199 二叉树的右视图

题目链接:https://leetcode.cn/problems/binary-tree-right-side-view/description/

image-20251202215319884

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if(root == null){
            return result;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            int record = 0;
            while(size > 0){
                TreeNode curNode = queue.poll();
                if(size == 1){
                    record = curNode.val;
                }
                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }
                size--;
            }
            result.add(record);
        }
        return result;
    }
}

LeetCode637 二叉树的层平均值

题目链接:https://leetcode.cn/problems/average-of-levels-in-binary-tree/description/

image-20251202220045917

class Solution {
    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> result = new ArrayList<>();
        if(root == null){
            return result;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            int cnt = size;
            double sum = 0;
            while(size > 0){
                TreeNode curNode = queue.poll();
                sum += curNode.val;

                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }
                size--;
            }
            double average = sum / cnt;
            result.add(average);
        }
        return result;
    }
}

LeetCode429 N叉树的层序遍历

题目链接:https://leetcode.cn/problems/n-ary-tree-level-order-traversal/description/

image-20251202220742794

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        List<List<Integer>> result = new ArrayList<>();
        if(root == null){
            return result;
        }

        Queue<Node> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            List<Integer> records = new ArrayList<>();
            while(size > 0){
                Node curNode = queue.poll();
                records.add(curNode.val);

                for(int i = 0;i < curNode.children.size();i++){
                    Node child = curNode.children.get(i);
                    if(child != null){
                        queue.offer(child);
                    }
                }
                size--;
            }
            result.add(records);
        }
        return result;
    }
}

LeetCode515 在每个树行中找最大值

题目链接:https://leetcode.cn/problems/find-largest-value-in-each-tree-row/description/

image-20251202221332865

class Solution {
    public List<Integer> largestValues(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if(root == null){
            return result;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            int maxNum = Integer.MIN_VALUE;
            while(size > 0){
                TreeNode curNode = queue.poll();
                if(maxNum < curNode.val){
                    maxNum = curNode.val;
                }

                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }
                size--;
            }
            result.add(maxNum);
        }
        return result;
    }
}

LeetCode116 填充每个节点的下一个右侧节点指针

题目链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/

image-20251202222819037

class Solution {
    public Node connect(Node root) {
        if(root == null){
            return root;
        }

        Queue<Node> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();

            Node preNode = queue.poll();
            if(preNode.left != null){
                queue.offer(preNode.left);
            }
            if(preNode.right != null){
                queue.offer(preNode.right);
            }
            size--;

            while(size > 0){
                Node curNode = queue.poll();
                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }
                size--;

                preNode.next = curNode;
                preNode = curNode;
            }
        }
        return root;
    }
}

LeetCode117 填充每个节点的下一个右侧节点指针Ⅱ

题目链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/

image-20251202222944962

class Solution {
    public Node connect(Node root) {
        if(root == null){
            return root;
        }

        Queue<Node> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();

            Node preNode = queue.poll();
            if(preNode.left != null){
                queue.offer(preNode.left);
            }
            if(preNode.right != null){
                queue.offer(preNode.right);
            }
            size--;

            while(size > 0){
                Node curNode = queue.poll();
                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }
                size--;

                preNode.next = curNode;
                preNode = curNode;
            }
        }
        return root;
    }
}

LeetCode104 二叉树的最大深度

题目链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/description/

image-20251202223511701

class Solution {
    public int maxDepth(TreeNode root) {
        int depth = 0;
        if(root == null){
            return depth;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            if(size > 0){
                depth++;
            }
            while(size > 0){
                TreeNode curNode = queue.poll();
                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }
                size--;
            }
        }
        return depth;
    }
}

LeetCode111 二叉树的最小深度

题目链接:https://leetcode.cn/problems/minimum-depth-of-binary-tree/description/

image-20251202223730934

class Solution {
    public int minDepth(TreeNode root) {
        int depth = 0;
        if(root == null){
            return depth;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            if(size > 0){
                depth++;
            }
            while(size > 0){
                TreeNode curNode = queue.poll();
                if(curNode.left != null){
                    queue.offer(curNode.left);
                }
                if(curNode.right != null){
                    queue.offer(curNode.right);
                }
                size--;

                if(curNode.left == null && curNode.right == null){
                    return depth;
                }
            }
        }
        return depth;
    }
}
posted @ 2025-12-02 22:40  SchwarzShu  阅读(0)  评论(0)    收藏  举报