文章目录
一、题目理解
题目链接:https://leetcode.cn/problems/binary-tree-inorder-traversal
题目描述:
给定一个二叉树的根节点 root ,返回它的 中序遍历(Left → Root → Right)。
示例:
输入:
1
\
2
/
3
输出:
[1, 3, 2]
二、中序遍历的核心概念
中序遍历(Inorder Traversal) 顺序规则如下:
- 访问左子树;
- 访问当前节点;
- 访问右子树。
即: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),在不使用栈或递归的情况下也能实现中序遍历。
核心思想:
- 如果当前节点没有左子树,访问它,然后走右子树。
- 如果有左子树,就找到左子树最右节点(前驱节点):
- 若其右指针为空,则将其右指针指向当前节点(建立线索),然后进入左子树;
- 若其右指针指向当前节点(说明左子树已访问完),则将其恢复空,访问当前节点,进入右子树。
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),未使用递归或栈 |