LeetCode Hot100(27/100)——94. 二叉树的中序遍历

文章目录

一、题目理解

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

题目描述:

给定一个二叉树的根节点 root ,返回它的 中序遍历(Left → Root → Right)。

示例:

输入:

复制代码
    1
     \
      2
     /
    3

输出:

复制代码
[1, 3, 2]

二、中序遍历的核心概念

中序遍历(Inorder Traversal) 顺序规则如下:

  1. 访问左子树;
  2. 访问当前节点;
  3. 访问右子树。

即:Left → Root → Right


思维导图

中序遍历
递归解法
访问左子树
访问根节点
访问右子树
迭代解法(栈)
使用栈模拟递归
不断向左入栈
弹出节点访问
转向右子树
Morris遍历(进阶)
不使用栈和递归
改变指针结构
空间O(1)


三、解法一:递归法(最容易理解)

思路:

递归本质是调用栈来管理访问顺序。每到一个节点,先递归访问它的左子树,再处理当前节点,最后访问它的右子树。


递归流程图



开始
当前节点为空?
返回
递归遍历左子树
访问当前节点,加入结果集
递归遍历右子树
结束


Java代码实现

java 复制代码
import java.util.*;

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

    private void dfs(TreeNode node, List<Integer> res) {
        if (node == null) return;
        dfs(node.left, res);
        res.add(node.val);
        dfs(node.right, res);
    }
}

复杂度分析

项目 分析
时间复杂度 O(n),每个节点被访问一次
空间复杂度 O(n),主要来自递归栈的深度(最坏为O(n))

四、解法二:迭代法(使用栈模拟递归)

思路:

  • 使用一个栈手动控制遍历顺序;
  • 不断向左走并压栈;
  • 当左边到底后,弹出节点访问,再转向右子树;
  • 重复这个过程直到栈为空且当前节点为空。

栈模拟流程图





初始化栈,当前节点为root
当前节点不为空或栈不为空?
结束
当前节点不为空?
将当前节点入栈,移动到左节点
弹出栈顶节点并访问
移动到右节点


Java实现代码

java 复制代码
import java.util.*;

public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode curr = root;

        while (curr != null || !stack.isEmpty()) {
            while (curr != null) {
                stack.push(curr);
                curr = curr.left;
            }
            curr = stack.pop();
            res.add(curr.val);
            curr = curr.right;
        }

        return res;
    }
}

复杂度分析

项目 分析
时间复杂度 O(n)
空间复杂度 O(n)(显式栈存储节点)

五、解法三(进阶):Morris遍历(O(1)空间)

原理:

Morris遍历通过在树中建立临时线索(Thread),在不使用栈或递归的情况下也能实现中序遍历。

核心思想:

  1. 如果当前节点没有左子树,访问它,然后走右子树。
  2. 如果有左子树,就找到左子树最右节点(前驱节点):
    • 若其右指针为空,则将其右指针指向当前节点(建立线索),然后进入左子树;
    • 若其右指针指向当前节点(说明左子树已访问完),则将其恢复空,访问当前节点,进入右子树。

Morris遍历时序图

前驱节点 左子树 当前节点 前驱节点 左子树 当前节点 寻找左子树的最右节点 若左子树不为空 找到左子树最右节点 建立右指针线索 左子树遍历 恢复右指针为空 访问节点并转向右子树


Java实现代码

java 复制代码
import java.util.*;

public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        TreeNode curr = root;

        while (curr != null) {
            if (curr.left == null) {
                res.add(curr.val);
                curr = curr.right;
            } else {
                TreeNode pre = curr.left;
                while (pre.right != null && pre.right != curr) {
                    pre = pre.right;
                }
                if (pre.right == null) {
                    pre.right = curr;
                    curr = curr.left;
                } else {
                    pre.right = null;
                    res.add(curr.val);
                    curr = curr.right;
                }
            }
        }
        return res;
    }
}

复杂度分析

项目 分析
时间复杂度 O(n),每个节点访问两次
空间复杂度 O(1),未使用递归或栈
相关推荐
GeekZHR2 小时前
C语言指针2:数组名、二级指针、指针数组,一次把“指针和数组“讲透
c语言·数据结构·算法·指针
h_a_o777oah2 小时前
【算法基础】卡特兰数:递推定义与折线对称公式推导及解题策略
c++·算法·acm·组合数学·卡特兰数·反射原理·动态规划dp
JAI科研2 小时前
Deepseek Agent Harness教程(二) | DeepSeek Harness 设计思路
人工智能·深度学习·算法·机器学习·自然语言处理·transformer·vllm
还不秃顶的计科生2 小时前
具身智能论文学习10:π0: A Vision-Language-Action Flow Model for General Robot Control
人工智能·深度学习·算法·机器学习·语言模型·vla·vlm
happyprince2 小时前
02-具体观 — Cordis 算法与实现剖析
算法
烬羽2 小时前
求第 K 大,为什么反而要用最小堆?
javascript·数据结构·算法
没落之王3 小时前
易学使者郑氏正脉郑冰推演马航事件
大数据·人工智能·算法·机器学习·可用性测试
阿部多瑞 ABU3 小时前
告别手工核图:基于 .NET + MuPDFCore 的 CAD 等轴测 PDF 材料表提取与新旧版本对比实战
后端·算法·ui·pdf·c#
郝学胜-神的一滴3 小时前
并查集深度入门:从玄学抽象到 QuickFind & QuickUnion 源码实战
数据结构·c++·python·程序人生·算法·软件开发
比奇堡裤头村3 小时前
统计学习方法——决策树
算法·决策树·学习方法