前言
二叉树遍历是算法入门必刷基础题,中序遍历遵循「左子树→根节点→右子树」的访问规则,是二叉搜索树有序输出的核心逻辑。本文以 LeetCode 第 94 题为载体,用 JavaScript 实现递归、栈迭代两种主流解法,拆解思路与优劣,适合前端算法入门读者。
题目分析
给定二叉树根节点root,返回中序遍历结果数组。示例输入:root = [1,null,2,3],二叉树结构为根 1、右子节点 2、2 的左子节点 3;按照左→根→右规则遍历,输出[1,3,2]。边界场景:空树返回空数组、单节点树返回仅含节点值的数组。
解法一:递归(简洁直观,入门首选)
核心思路
递归天然符合深度优先遍历逻辑,递归终止条件:当前节点为空直接返回。执行顺序固定:递归左子树 → 记录当前节点值 → 递归右子树。
完整代码
javascript
运行
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
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;
};
优缺点
优势:代码仅十余行,逻辑零理解成本,快速通过测试用例;劣势:依赖函数调用栈,树深度极大时会触发栈溢出,面试中大数据场景不推荐。
解法二:栈迭代(面试高频,规避递归溢出)
核心思路
手动用数组模拟递归调用栈,指针持续遍历左节点并入栈,无左节点时弹出栈顶记录数值,再切换处理右子树,循环直至指针为空且栈无元素。
完整代码
javascript
运行
var inorderTraversal = function(root) {
const res = [];
const stack = [];
let cur = root;
while (cur || stack.length) {
// 遍历至最左侧叶子节点
while (cur) {
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
res.push(cur.val);
// 处理右子树
cur = cur.right;
}
return res;
};
执行流程示例(样例树)
- cur=1,入栈,cur 指向 null;
- 弹出 1,存入结果,cur 切换至右节点 2;
- cur=2 入栈,cur 指向左节点 3;
- cur=3 入栈,cur 指向 null;
- 弹出 3 存入结果,cur 为 null;
- 弹出 2 存入结果,cur 为 null;循环结束,输出
[1,3,2]。
两种方案对比总结
- 递归:适合刷题快速解题、理解遍历逻辑,深度过大会栈溢出;
- 栈迭代:无递归深度限制,时间复杂度 O (n)、空间 O (n),面试官更爱考察。
结尾
二叉树前、中、后序遍历逻辑相通,仅调整节点记录顺序。吃透中序迭代写法,能快速举一反三掌握另外两种遍历,为二叉搜索树、路径求和等中等难度题目打好基础。