数据结构和算法之【二叉树】

目录

认识二叉树

二叉树的遍历

广度优先遍历

深度优先遍历

前序遍历

中序遍历

后序遍历

LeetCode-102题(二叉树的层序遍历)

题解

测试结果

LeetCode-144题(二叉树的前序遍历)

题解

方法一:借助栈来解题

方法二:使用递归解题

测试结果

LeetCode-94题(二叉树的中序遍历)

题解

方法一:借助栈来解题

方法二:使用递归解题

测试结果

LeetCode-145题(二叉树的后序遍历)

题解

方法一:借助栈来解题

方法二:使用递归解题

测试结果


认识二叉树

二叉树中每个节点最多有2个子节点,最顶层的节点称为根节点,没有字节点的称为叶子节点

如上图中的二叉树:

  • 节点1和节点3有2个子节点,节点2有1个子节点,其余节点没有子节点
  • 节点1为二叉树中最顶层的节点,它就是根节点
  • 节点4、节点5和节点6没有子节点,它们是叶子节点

二叉树的遍历

分为两种遍历方式:广度优先遍历和深度优先遍历

广度优先遍历

也叫程序遍历,优先访问距离根节点最近的节点

深度优先遍历

对于二叉树,深度优先遍历又分为如下3种遍历方法

前序遍历

对于每一棵子树,先访问当前节点,然后是左子树,最后是右子树

中序遍历

对于每一棵子树,先访问左子树,然后是当前节点,最后是右子树

后序遍历

对于每一棵子树,先访问左子树,然后是右子树,最后是当前节点

LeetCode-102题(二叉树的层序遍历)

题解

java 复制代码
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        // 借助队列来解题
        LinkedList<TreeNode> queue = new LinkedList<>();
        // 将根节点入队
        queue.offer(root);
        // 记录当前层的节点数(当前第一层,只有一个节点,根节点)
        int c1 = 1;
        // 只要队列不为空
        while (!queue.isEmpty()) {
            // 定义集合存储每一层的节点的值
            List<Integer> nodeValInnerList = new ArrayList<>();
            // 用于记录下一层的节点数量
            int c2 = 0;
            // 处理每一层节点
            for (int i = 0; i < c1; i++) {
                TreeNode currTreeNode = queue.poll();
                nodeValInnerList.add(currTreeNode.val);
                if (currTreeNode.left != null) {
                    queue.offer(currTreeNode.left);
                    c2++;
                }
                if (currTreeNode.right != null) {
                    queue.offer(currTreeNode.right);
                    c2++;
                }
            }
            result.add(nodeValInnerList);
            c1 = c2;
        }
        return result;
    }
}

测试结果

LeetCode-144题(二叉树的前序遍历)

题解

方法一:借助栈来解题

java 复制代码
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        order(root, result);
        return result;
    }

    private void order(TreeNode root, List<Integer> pre) {
        //当前节点
        TreeNode curr = root;
        //借助栈
        LinkedList<TreeNode> stack = new LinkedList<>();
        //最近一次pop的元素
        TreeNode pop = null;
        while (curr != null || !stack.isEmpty()) {
            if (curr != null) {
                stack.push(curr);
                pre.add(curr.val);
                //待处理左节点
                curr = curr.left;
            } else {
                //栈不为空
                TreeNode peek = stack.peek();
                //右节点为空
                if (peek.right == null) {
                    pop = stack.pop();
                }
                //右节点处理完
                else if (peek.right == pop) {
                    pop = stack.pop();
                }
                //处理右节点
                else {
                    curr = peek.right;
                }
            }
        }
    }
}

方法二:使用递归解题

java 复制代码
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        preOrder(root, result);
        return result;
    }

    /**
     * 二叉树的前序遍历(使用递归方式)
     */
    private void preOrder(TreeNode node, List<Integer> result) {
        // 递归的结束条件
        if (node == null) {
            return;
        }
        // 当前节点
        result.add(node.val);
        // 处理左子树
        preOrder(node.left, result);
        // 处理右子树
        preOrder(node.right, result);
    }
}

测试结果

LeetCode-94题(二叉树的中序遍历)

题解

方法一:借助栈来解题

java 复制代码
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        order(root, result);
        return result;
    }

    private void order(TreeNode root, List<Integer> mid) {
        //当前节点
        TreeNode curr = root;
        //借助栈
        LinkedList<TreeNode> stack = new LinkedList<>();
        //最近一次pop的元素
        TreeNode pop = null;
        while (curr != null || !stack.isEmpty()) {
            if (curr != null) {
                stack.push(curr);
                //待处理左节点
                curr = curr.left;
            } else {
                //栈不为空
                TreeNode peek = stack.peek();
                //右节点为空
                if (peek.right == null) {
                    mid.add(peek.val);
                    pop = stack.pop();
                }
                //右节点处理完
                else if (peek.right == pop) {
                    pop = stack.pop();
                }
                //处理右节点
                else {
                    mid.add(peek.val);
                    curr = peek.right;
                }
            }
        }
    }
}

方法二:使用递归解题

java 复制代码
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        inOrder(root, result);
        return result;
    }

    /**
     * 二叉树的中序遍历(使用递归方式)
     */
    private void inOrder(TreeNode node, List<Integer> result) {
        // 递归的结束条件
        if (node == null) {
            return;
        }
        // 处理左子树
        inOrder(node.left, result);
        // 当前节点
        result.add(node.val);
        // 处理右子树
        inOrder(node.right, result);
    }
}

测试结果

LeetCode-145题(二叉树的后序遍历)

题解

方法一:借助栈来解题

java 复制代码
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        order(root, result);
        return result;
    }

    private void order(TreeNode root, List<Integer> post) {
        //当前节点
        TreeNode curr = root;
        //借助栈
        LinkedList<TreeNode> stack = new LinkedList<>();
        //最近一次pop的元素
        TreeNode pop = null;
        while (curr != null || !stack.isEmpty()) {
            if (curr != null) {
                stack.push(curr);
                //待处理左节点
                curr = curr.left;
            } else {
                //栈不为空
                TreeNode peek = stack.peek();
                //右节点为空
                if (peek.right == null) {
                    pop = stack.pop();
                    post.add(peek.val);
                }
                //右节点处理完
                else if (peek.right == pop) {
                    pop = stack.pop();
                    post.add(peek.val);
                }
                //处理右节点
                else {
                    curr = peek.right;
                }
            }
        }
    }
}

方法二:使用递归解题

java 复制代码
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        postOrder(root, result);
        return result;
    }

    /**
     * 二叉树的后序遍历(使用递归方式)
     */
    private void postOrder(TreeNode node, List<Integer> result) {
        // 递归的结束条件
        if (node == null) {
            return;
        }
        // 处理左子树
        postOrder(node.left, result);
        // 处理右子树
        postOrder(node.right, result);
        // 当前节点
        result.add(node.val);
    }
}

测试结果

相关推荐
考虑考虑7 小时前
JDK26中的Map.ofLazy
java·后端·java ee
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 14 章 MCP 服务端(上):注解式实现与工具来源
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 15 章 MCP 服务端(下):三种协议形态、Streamable 传输与状态管理
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 16 章 向量存储(上):`VectorStore` 接口体系、`BatchingStrategy`
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 12 章 工具循环的流式形态、Usage 累加与扩展体系
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 23 章 模型供应商实现:从 `OpenAiSetup` 到 Bedrock
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 06 章 内置 Advisor 全景:13 个实现逐个剖到源码级
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 03 章 消息体系与 Prompt:不可变模型、`ChatOptions` 与模板渲染
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 24 章 生产实践与 2.x 迁移:陷阱清单、AOT 与调优
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 10 章 工具调用(中):执行链路、结果转换与工具限制
java·人工智能·开源