《代码随想录》--二叉树

《代码随想录》--二叉树

1、二叉树的递归遍历

前序遍历

中序遍历

后序遍历

代码

  • 前序遍历
java 复制代码
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        preOrder(root,list);
        return list;
    }
    public void preOrder(TreeNode root,List<Integer> list){
        if(root == null) return;
        list.add(root.val);
        preOrder(root.left,list);
        preOrder(root.right,list);
    }
}
  • 中序遍历
java 复制代码
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        inOrder(root,list);
        return list;
    }
    public void inOrder(TreeNode root,List<Integer> list){
        if(root == null) return;
        inOrder(root.left,list);
        list.add(root.val);
        inOrder(root.right,list);
    }
}
  • 后序遍历
java 复制代码
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        postOrder(root,list);
        return list;
    }
    public void postOrder(TreeNode root,List<Integer> list){
        if(root == null) return;
        postOrder(root.left,list);
        postOrder(root.right,list);
        list.add(root.val);
    }
}

2、二叉树的迭代遍历

前序遍历

中序遍历

后序遍历

代码

  • 前序遍历
java 复制代码
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if(root == null) return result;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            result.add(node.val);
            if(node.right != null) stack.push(node.right);
            if(node.left != null) stack.push(node.left);
        }
        return result;
    }
}
  • 中序遍历
java 复制代码
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()){
            if(cur != null){
                stack.push(cur);
                cur = cur.left;
            }else{
                TreeNode node = stack.pop();
                list.add(node.val);
                cur = node.right;
            }
        }
        return list;
    }
}
  • 后序遍历
java 复制代码
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null) return list;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            list.add(node.val);
            if(node.left != null) stack.push(node.left);
            if(node.right != null) stack.push(node.right);
        }
        Collections.reverse(list);
        return list;
    }
}

分析

  • 非递归的遍历都需要借助来编写代码
  • 前序遍历:
    • 前序遍历是中左右的顺序
    • 先把中间节点放入栈中
    • 再放入右孩子(为什么?因为栈先入后出)
    • 再放入左孩子
  • 中序遍历:
    • 中序遍历的顺序是左中右,但是我们的处理顺序和访问顺序不一致,所以借助指针
    • 定义一个cur指针帮助我们遍历,栈用来处理节点上的元素
  • 后序遍历:
    • 后序遍历的顺序是左右中,可以根据前序遍历改变得到
    • 将遍历顺序改为中左右,最后得到的结果是中右左
    • 反转数组得到正确结果

3、统一风格的迭代遍历代码

  • 前面的迭代遍历代码风格不统一,不像递归代码一样修改代码的位置就能写出三种遍历方式
  • 这里借助空节点标记法

代码

  • 前序
java 复制代码
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root != null) stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node != null){
                node = stack.pop();
                if(node.right != null) stack.push(node.right);
                if(node.left != null) stack.push(node.left);
                stack.push(node);
                stack.push(null);
            }else{
                stack.pop();
                node = stack.pop();
                list.add(node.val);
            }
        }
        return list;
    }
}
  • 中序
java 复制代码
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root != null) stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node != null){
                node = 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(); //取出栈中元素
                list.add(node.val);
            }
        }
        return list;
    }
}
  • 后序
java 复制代码
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root != null) stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(node != null){
                node = stack.pop();
                stack.push(node);
                stack.push(null);
                if(node.right != null) stack.push(node.right);
                if(node.left != null) stack.push(node.left);
            }else{
                stack.pop();
                node = stack.pop();
                list.add(node.val);
            }
        }
        return list;
    }
}

分析

  • 可以看到使用空节点标记法,只需要修改两行代码就能写出不同的遍历代码

4、二叉树的层序遍历

学会二叉树的层序遍历,可以一口气打完以下十题:

代码 102题

  • 迭代
java 复制代码
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        if(root == null) return list;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            List<Integer> tempList = new ArrayList<>();
            int len = queue.size();
            while(len > 0){
                TreeNode node = queue.poll();
                tempList.add(node.val);
                if(node.left != null) queue.offer(node.left);
                if(node.right != null) queue.offer(node.right);
                len--;
            }
            list.add(tempList);
        }
        return list;
    }
}
  • 递归
java 复制代码
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        level(root,list,0);
        return list;
    }
    public void level(TreeNode node,List<List<Integer>> list,int depth){
        if(node == null) return;
        depth++;
        if(list.size() < depth){
            List<Integer> tempList = new ArrayList<>();
            list.add(tempList);
        }
        list.get(depth-1).add(node.val);
        level(node.left,list,depth);
        level(node.right,list,depth);
    }
}

分析

  • 迭代法借助了数据结构队列,先入先出。
相关推荐
一路向北North11 小时前
Spring Security OAuth2.0(19):JWT令牌
java·后端·spring
玛卡巴卡ldf11 小时前
【LeetCode 手撕算法】(细节知识点总结)
java·数据结构·算法·leetcode·力扣
一叶飘零_sweeeet12 小时前
IDEA 插件 Trae AI 最新全攻略(基于 TRAE AI: Coding Assistant 1.7.0.0)
java·intellij-idea·trae
KobeSacre12 小时前
CyclicBarrier 源码
java·jvm·算法
MacroZheng12 小时前
给Claude Code装上这款炫酷的HUD插件,状态信息就一目了然了!
java·人工智能·后端
我登哥MVP12 小时前
Hadoop成长史-从Nutch子项目到大数据生态王者
java·大数据·hadoop·分布式·云原生·云计算
进击切图仔12 小时前
SAM3 微调标注流水线和 Label Studio
java·服务器·前端
java1234_小锋12 小时前
Maven 4 要来了:15 年后,Java 构建工具迎来“彻底重构“
java·重构·maven
霸道流氓气质13 小时前
Java 工程师 AI 智能体学习路线 · 阶段 1:AI / LLM 基础认知 详解
java·人工智能·学习
JerrySir13 小时前
`spring.threads.virtual.enabled=true`:用三类负载定位等待、争用与拒绝
java·spring boot