LeetCode 94. 二叉树的中序遍历题解

2 阅读2分钟

题目描述

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

中序遍历的访问顺序为:左子树 → 根节点 → 右子树


解题思路

二叉树的中序遍历是算法面试中的基础题,通常有两种主流的解法:递归法和迭代法。

方法一:递归法(最直观)

递归是二叉树最自然的遍历方式。我们将大问题拆解为小问题:

  1. 递归遍历当前节点的左子树。
  2. 访问(记录)当前节点的值。
  3. 递归遍历当前节点的右子树。
  4. 终止条件:当节点为 null 时,直接返回。

方法二:迭代法(使用栈模拟)

如果不允许使用递归,我们需要手动维护一个栈(Stack) 来模拟系统底层的函数调用栈。
核心思想是 “一路向左,撞墙回头”

  1. 准备一个指针 current 指向根节点。
  2. 一路向左:只要 current 不为空,就将当前节点压入栈中,并让 current 指向它的左子节点。
  3. 撞墙回头:当 current 为空时,说明左子树已经到底了。此时从栈顶弹出一个节点,访问该节点的值。
  4. 转向右子树:将 current 指向刚刚弹出节点的右子节点,准备开启下一轮循环。
  5. 循环条件:只要 current 不为空,或者栈中还有未处理的节点,就继续循环。

JavaScript 代码实现

1. 递归实现

var inorderTraversal = function(root) {
    const res = [];
    
    const dfs = (node) => {
        if (!node) return; // 递归终止条件
        dfs(node.left);    // 遍历左子树
        res.push(node.val);// 访问根节点
        dfs(node.right);   // 遍历右子树
    };
    
    dfs(root);
    return res;
};

2. 迭代实现(推荐掌握)

var inorderTraversal = function(root) {
    const res = [];
    const stack = [];
    let current = root;
    
    // 当当前节点不为空,或者栈不为空时,继续遍历
    while (current !== null || stack.length > 0) {
        // 1. 一路向左,将沿途节点全部压入栈中
        while (current !== null) {
            stack.push(current);
            current = current.left;
        }
        
        // 2. 左边走到底了,弹出栈顶节点(即最左侧的节点)
        current = stack.pop();
        // 3. 访问该节点
        res.push(current.val);
        // 4. 转向该节点的右子树
        current = current.right;
    }
    
    return res;
};

复杂度分析

  • 时间复杂度: O(n)O(n) ,其中 nn 是二叉树的节点数。每个节点都会被精确地访问一次。

  • 空间复杂度: O(h)O(h) ,其中 hh 是二叉树的高度。

    • 递归法消耗的是系统调用栈的空间。
    • 迭代法消耗的是我们手动创建的栈的空间。
    • 在最坏情况下(树退化为链表),空间复杂度为 O(n)O(n) ;在最好情况下(完全平衡二叉树),空间复杂度为 O(log⁡n)O(logn) 。