【力扣100题】26. 二叉树的中序遍历

一、题目描述

给定一个二叉树的根节点 root,返回它的 中序遍历 结果。

中序遍历的顺序是:左子树 -> 根节点 -> 右子树

示例

示例 输入 输出
示例1 [1,null,2,3] [1,3,2]
示例2 [] []
示例3 [1] [1]

提示

  • 树中节点数目在范围 [0, 100]
  • -100 <= Node.val <= 100

进阶

递归算法很简单,你可以通过迭代算法完成吗?


二、解题思路总览

方法 核心思想 关键数据结构 时间复杂度 空间复杂度
递归 左-根-右的递归顺序 函数调用栈 O(n) O(h),h为树高
迭代 模拟栈手动回溯 显式栈 O(n) O(h)

递归与迭代的选择

  • 递归:代码简洁,但有函数调用开销
  • 迭代:需要手动管理栈,但更通用

三、完整代码

方法一:递归

cpp 复制代码
class Solution {
public:
    // 递归函数:中序遍历
    void dfs(TreeNode* root) {
        if (!root) return;           // 1. 空节点,返回
        dfs(root->left);             // 2. 递归遍历左子树
        ans.push_back(root->val);    // 3. 访问根节点
        dfs(root->right);            // 4. 递归遍历右子树
    }

    vector<int> ans;                  // 存放遍历结果

    vector<int> inorderTraversal(TreeNode* root) {
        dfs(root);                    // 调用递归函数
        return ans;                   // 返回结果
    }
};

方法二:迭代

cpp 复制代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;              // 存放遍历结果
        stack<TreeNode*> stk;         // 模拟递归栈

        while (root != NULL || !stk.empty()) {
            // 1. 一直向左走,把经过的节点入栈
            while (root != NULL) {
                stk.push(root);
                root = root->left;
            }

            // 2. 处理栈顶节点
            root = stk.top();
            stk.pop();
            ans.push_back(root->val);

            // 3. 切换到右子树
            root = root->right;
        }

        return ans;
    }
};

四、算法流程图(ASCII)

递归版流程

复制代码
                    ┌─────────────────────────┐
                    │     调用 dfs(root)      │
                    └───────────┬─────────────┘
                                │
                                ▼
                    ┌─────────────────────────┐
                    │   if (!root) return ?    │
                    └───────────┬─────────────┘
                           Yes /  \ No
                              /    \
                             ▼      ▼
                   ┌───────────┐   ┌─────────────────────────┐
                   │   返回    │   │   dfs(root->left)      │
                   └───────────┘   │   (递归左子树)           │
                                   └───────────┬─────────────┘
                                               │
                                               ▼
                                   ┌─────────────────────────┐
                                   │   ans.push_back(val)    │
                                   │   (访问根节点)           │
                                   └───────────┬─────────────┘
                                               │
                                               ▼
                                   ┌─────────────────────────┐
                                   │   dfs(root->right)     │
                                   │   (递归右子树)           │
                                   └─────────────────────────┘

迭代版流程

复制代码
初始化:ans=[], stk=[], root指向根节点

                    ┌───────────────────────────────────────┐
                    │          while循环开始                 │
                    │   (root != NULL || !stk.empty())      │
                    └───────────────────┬───────────────────┘
                                        │
                    ┌───────────────────┴───────────────────┐
                    │                                       │
                    ▼                                       ▼
          ┌──────────────────┐                 ┌──────────────────┐
          │ root != NULL ?   │──── Yes ────→   │ stk.push(root)   │
          └────────┬─────────┘                 │ root = root->left│
                   │ No                         └──────────────────┘
                   │                                   │
                   │                                   │ (循环向左)
                   │                                   │
                   │    ┌──────────────────────────────┘
                   │    │
                   │    │         ┌──────────────────┐
                   │    └─────┐   │ root = stk.top()│
                   │          │   │ stk.pop()       │
                   │          │   │ ans.push_back()  │
                   │          │   │ root = root->right│
                   │          │   └────────┬─────────┘
                   │          │            │
                   │          ▼            │
                   │    ┌──────────────────┴───┐
                   │    │   返回循环继续       │
                   │    └──────────────────┘
                   ▼
          ┌──────────────────┐
          │   while循环结束   │
          │   返回 ans        │
          └──────────────────┘

五、逐行解析

递归版逐行解析

cpp 复制代码
class Solution {
public:
    void dfs(TreeNode* root) {
        // ─────────────────────────────────────────
        // 第1步:递归终止条件
        // 空节点直接返回,不做任何处理
        // ─────────────────────────────────────────
        if (!root) return;

        // ─────────────────────────────────────────
        // 第2步:递归遍历左子树
        // 中序遍历顺序:左-根-右,所以先遍历左子树
        // ─────────────────────────────────────────
        dfs(root->left);

        // ─────────────────────────────────────────
        // 第3步:访问根节点
        // 左子树遍历完成后,将根节点值加入结果
        // ─────────────────────────────────────────
        ans.push_back(root->val);

        // ─────────────────────────────────────────
        // 第4步:递归遍历右子树
        // 最后遍历右子树
        // ─────────────────────────────────────────
        dfs(root->right);
    }

    // ─────────────────────────────────────────
    // 结果存储
    // 作为成员变量,方便递归过程中累积结果
    // ─────────────────────────────────────────
    vector<int> ans;

    vector<int> inorderTraversal(TreeNode* root) {
        dfs(root);   // 调用递归函数
        return ans;  // 返回遍历结果
    }
};

迭代版逐行解析

cpp 复制代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;          // 存放遍历结果
        stack<TreeNode*> stk;     // 显式栈,模拟递归

        // ─────────────────────────────────────────
        // 外层循环:处理完所有节点才结束
        // root != NULL:有节点还没处理完
        // !stk.empty():栈中还有待处理的节点
        // ─────────────────────────────────────────
        while (root != NULL || !stk.empty()) {

            // ─────────────────────────────────────────
            // 内层循环:一直向左走到尽头
            // 目的:找到最左下的节点
            // 同时把路径上的每个节点入栈保存
            // ─────────────────────────────────────────
            while (root != NULL) {
                stk.push(root);      // 入栈,保存节点以便后续回溯
                root = root->left;    // 继续向左走
            }

            // ─────────────────────────────────────────
            // 此时root为NULL,已到达最左下的空节点
            // 从栈中弹出最近保存的节点
            // ─────────────────────────────────────────
            root = stk.top();         // 栈顶节点
            stk.pop();               // 弹出

            // ─────────────────────────────────────────
            // 处理栈顶节点(根节点)
            // 这就是中序遍历的"根"步骤
            // ─────────────────────────────────────────
            ans.push_back(root->val);

            // ─────────────────────────────────────────
            // 切换到右子树
            // 处理完根节点后,处理右子树
            // 右子树会重复同样的过程
            // ─────────────────────────────────────────
            root = root->right;
        }

        return ans;
    }
};

六、复杂度分析

时间复杂度

方法 分析 复杂度
递归 每个节点访问一次 O(n)
迭代 每个节点访问一次 O(n)

推导

  • 二叉树有 n 个节点
  • 每个节点都会被访问一次(入栈一次、出栈一次)
  • 因此时间复杂度是 O(n)

空间复杂度

方法 分析 复杂度
递归 函数调用栈,最大深度为树高h O(h)
迭代 显式栈,最大深度为树高h O(h)

推导

  • 树高为 h(h 取值 1~n)
  • 最坏情况(链表形状):h = n,复杂度 O(n)
  • 平衡树情况:h = log n,复杂度 O(log n)

七、面试追问 FAQ

问题 回答
递归和迭代哪个更好? 递归代码简洁,迭代更通用。面试中可以先写递归,再写迭代展示能力。
递归的缺点是什么? 有函数调用开销,可能导致栈溢出(树深度过大时)。
迭代如何避免栈溢出? 用显式栈(堆内存)代替系统栈,但复杂度相同。
前序遍历和后序遍历的递归顺序是什么? 前序:根-左-右。后序:左-右-根。
中序遍历有什么用? BST(二叉搜索树)中序遍历得到有序序列。

八、相关题目

题目 难度 关键点
94. 二叉树的中序遍历 简单 本题
144. 二叉树的前序遍历 简单 根-左-右顺序
145. 二叉树的后序遍历 简单 左-右-根顺序
98. 验证二叉搜索树 中等 中序遍历+有序性判断
230. 二叉搜索树中第K小的元素 中等 BST中序遍历
94. 二叉树的中序遍历(迭代) 简单 手动栈模拟

九、总结

对比项 递归 迭代
代码量 少(4行核心代码) 多(需要手动管理栈)
可读性 高,符合递归思维 较低,栈操作复杂
系统开销 函数调用开销 无函数调用
栈溢出风险 有(深度过深时) 无(显式栈在堆上)
面试建议 先写,展示基本功 进阶写,展示迭代能力

核心思想

  • 递归:系统帮你管理栈,代码简洁
  • 迭代:手动模拟栈过程,需要两个循环(外层处理节点,内层一直向左)

相关推荐
sheeta19981 小时前
LeetCode 每日一题笔记 日期:2026.05.11 题目:2553. 分割数组中数字的数位
笔记·算法·leetcode
ZPC82101 小时前
规划后的轨迹,如何发给 moveit_servo 执行
c++·人工智能·算法·3d
70asunflower1 小时前
5.4 分布分析
人工智能·算法·机器学习·数据挖掘·数据分析
Pkmer2 小时前
滑动窗口专题
算法
Omics Pro2 小时前
柳叶刀|参考文献不存在
人工智能·算法·机器学习·支持向量机·自然语言处理
初心未改HD2 小时前
机器学习之K-Means聚类算法详解
算法·机器学习·kmeans
yugi9878382 小时前
主动噪声控制中的 FXLMS 算法研究与 MATLAB 实现
开发语言·算法·matlab
Liangwei Lin2 小时前
LeetCode 394. 字符串解码
数据结构·算法
YuanDaima20482 小时前
动态规划基础原理与题目说明
数据结构·人工智能·python·算法·动态规划·手撕代码