LeetCode 热题 100——二叉树——二叉树的中序遍历

37. 二叉树的中序遍历

题目描述

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

示例 1:

输入:root = 1,null,2,3

输出:1,3,2

示例 2:

输入:root = \[\]

输出:\[\]

示例 3:

输入:root = 1

输出:1

提示:

树中节点数目在范围 0, 100

-100 <= Node.val <= 100

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

求解

回忆回忆二叉树的相关概念:

二叉树的前序、中序、后序遍历是 ** 深度优先遍历**(DFS) 的三种核心方式,区别在于访问根节点、左子树、右子树的顺序不同。先明确几个概念:

根节点 :当前子树的根(或整棵树的根);
左子树 :根节点的左孩子为根的子树;
右子树:根节点的右孩子为根的子树。

一、前序遍历(根→左→右)

顺序:先访问根节点,再递归遍历左子树,最后递归遍历右子树。"前" 指根节点在遍历顺序中排在左、右子树之前。

示例(二叉树结构):

htmlplaintext 复制代码
    1
   / \
  2   3
 / \
4   5

前序遍历结果:1 → 2 → 4 → 5 → 3

核心逻辑(递归):

javascript 复制代码
function preorderTraversal(root) {
    const res = [];
    const dfs = (node) => {
        if (!node) return;
        res.push(node.val); // 先访问根
        dfs(node.left);     // 再遍历左子树
        dfs(node.right);    // 最后遍历右子树
    };
    dfs(root);
    return res;
}

二、中序遍历(左→根→右)

顺序:先递归遍历左子树,再访问根节点,最后递归遍历右子树。"中" 指根节点在遍历顺序中排在左子树之后、右子树之前。

示例(同上二叉树):

中序遍历结果:4 → 2 → 5 → 1 → 3

核心逻辑(递归):

javascript 复制代码
function inorderTraversal(root) {
    const res = [];
    const dfs = (node) => {
        if (!node) return;
        dfs(node.left);     // 先遍历左子树
        res.push(node.val); // 再访问根
        dfs(node.right);    // 最后遍历右子树
    };
    dfs(root);
    return res;
}

特殊性质:

二叉搜索树(BST)的中序遍历结果是严格升序的,这是 BST 的重要特征。

三、后序遍历(左→右→根)

顺序:先递归遍历左子树,再递归遍历右子树,最后访问根节点。"后" 指根节点在遍历顺序中排在左、右子树之后。

示例(同上二叉树):

后序遍历结果:4 → 5 → 2 → 3 → 1

核心逻辑(递归):

javascript 复制代码
function postorderTraversal(root) {
    const res = [];
    const dfs = (node) => {
        if (!node) return;
        dfs(node.left);     // 先遍历左子树
        dfs(node.right);    // 再遍历右子树
        res.push(node.val); // 最后访问根
    };
    dfs(root);
    return res;
}

特殊性质:

后序遍历常用于删除树节点(先删子节点,再删根)、计算子树和等场景。

四、总结对比

遍历方式 顺序 核心特点 典型应用
前序 根→左→右 根节点最先访问 复制树、序列化树
中序 左→根→右 BST 遍历结果升序 验证 BST、找 BST 的最值
后序 左→右→根 根节点最后访问 删除树、计算子树高度 / 和

记忆技巧:

  • 前序:根在最前;
  • 中序:根在中间;
  • 后序:根在最后;
    (左子树永远在右子树之前遍历)。

代码实现如下:

js 复制代码
var inorderTraversal = function(root) {
    // 先写递归
    // 中序遍历:左 根 右
    let ans = [];
    const dfs = (node) => {
        if (!node) return null;
        dfs(node.left); // 先遍历左边
        ans.push(node.val); // 访问根节点
        dfs(node.right); // 在遍历右边
    }
    dfs(root);
    return ans;
};

进阶:(使用迭代遍历)

js 复制代码
var inorderTraversal = function(root) {
    // 迭代: 使用 栈
    // 中序遍历:左 根 右
    let ans = [];
    let stk = []; // 定义一个栈
    while (root || stk.length !== 0) {
        while(root) {
            stk.push(root);
            root = root.left;
        }
        root = stk.pop();
        ans.push(root.val);
        root = root.right;
    }
    return ans;
};

在题解中 有一个特别厉害的方法,作者称为"颜色标记法 " ,兼具栈迭代方法的高效,又像递归方法一样简洁易懂,更重要的是,这种方法对于前序、中序、后序遍历,能够写出完全一致的代码。链接

其核心思想如下:

  • 使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
  • 如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
  • 如果遇到的节点为灰色,则将节点的值输出。

代码如下:

js 复制代码
var inorderTraversal = function(root) {
    // 迭代: 使用 栈
    // 中序遍历:左 根 右
    let ans = [];
    let stk = [{ node: root, flag: 0}]; // 定义一个栈
    while (stk.length !== 0) {
        const {node, flag} = stk.pop()
        if (!node) continue;
        if (flag === 0) {
            stk.push({node: node.right, flag: 0})
            stk.push({node: node, flag: 1})
            stk.push({node: node.left, flag: 0})
        } else {
            ans.push(node.val);
        }
    }
    return ans;
};
相关推荐
谙弆悕博士8 小时前
系统集成项目管理工程师教程(第3版)笔记——第17章:法律法规和标准规范
笔记·职场和发展·学习方法·业界资讯·软考·法律·法规
烬羽9 小时前
递归老写崩?一个"退回"公式,把回溯题变成填空题
javascript·深度学习·算法
闪电悠米9 小时前
力扣hot100-41.缺失的第一个正数-原地哈希详解
数据结构·算法·哈希算法
星空露珠10 小时前
28种颜色对应名称,
开发语言·数据库·算法·游戏·lua
QXWZ_IA12 小时前
桥梁数字孪生怎么落地?
人工智能·科技·算法·智能硬件·政务
Kel12 小时前
输出层与反分词(Output Layer & Detokenization)
人工智能·算法·架构
陕西企来客12 小时前
2026年7月技术好GEO优化方案:算法适配与内容策略
人工智能·算法·机器学习·技术好geo优化
风栖柳白杨12 小时前
【面试】AI算法工程师_空白自测版本
人工智能·算法·面试
imbackneverdie13 小时前
知网官宣:禁止 AI 列为论文署名作者,标注 Gemini、DeepSeek 等 AI 为作者的稿件统一下架
大数据·人工智能·ai·职场和发展·aigc·科研·高校
闪电悠米14 小时前
力扣hot100-73.矩阵置零-标记数组详解
算法·leetcode·矩阵