🔥个人主页: Milestone-里程碑
❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>
🌟心向往之行必能至
一、题目回顾
二叉树中序遍历 :按照 左子树 → 根节点 → 右子树 的顺序访问节点。
要求:不用递归 ,用 栈 + 迭代 实现。
二、完整可运行代码
cpp
运行
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
TreeNode* cur = root; // 当前遍历节点
vector<int> v; // 存储结果
stack<TreeNode*> st; // 迭代必备栈
// 循环条件:当前节点不为空 或 栈不为空
while (cur || !st.empty())
{
// 1. 一路向左,把所有左节点入栈
while (cur)
{
st.push(cur);
cur = cur->left;
}
// 2. 走到最左,cur 为空,弹出栈顶(根节点)
TreeNode* top = st.top();
st.pop();
// 3. 访问根节点(中序核心位置)
v.push_back(top->val);
// 4. 转向右子树
cur = top->right;
}
return v;
}
};
三、核心思路(超级好记)
中序遍历:左 → 根 → 右
迭代版的逻辑可以总结为 4 步:
- 一路向左走到底,把经过的节点全部压入栈
- 走到最左边(
cur == nullptr) - 弹出栈顶 = 根节点,加入结果
- 去遍历右子树
完美对应中序遍历规则!
四、逐行代码精讲
1. 变量定义
cpp
运行
TreeNode* cur = root; // 当前走到的节点
vector<int> v; // 保存遍历结果
stack<TreeNode*> st; // 用栈记录回溯路径
2. 外层循环
cpp
运行
while (cur || !st.empty())
- 只要当前节点不为空 或 栈里还有节点没处理,就继续循环
3. 内层循环:一路向左
cpp
运行
while (cur) {
st.push(cur);
cur = cur->left;
}
- 把所有左孩子依次入栈
- 直到走到
nullptr(最左下角)
4. 弹出栈顶 → 访问根节点
cpp
运行
TreeNode* top = st.top();
st.pop();
v.push_back(top->val);
- 此时弹出的就是左子树遍历完的根节点
- 这一行就是中序遍历的访问位置
5. 走向右子树
cpp
运行
cur = top->right;
- 根访问完,去遍历右子树
五、执行流程(秒懂)
举个最简单的树:
plaintext
1
\
2
/
3
遍历顺序:1 → 3 → 2
执行步骤:
- cur=1,入栈 → 左为空
- 弹出 1 → 加入结果
- cur=1 的右孩子 2
- cur=2,入栈 → 左走 3
- cur=3,入栈 → 左为空
- 弹出 3 → 加入结果
- cur=3 的右为空
- 弹出 2 → 加入结果
- 结束
最终结果:[1,3,2] ✅
六、为什么这是最优写法?
- 时间复杂度 O (n):每个节点入栈出栈各一次
- 空间复杂度 O (n):最坏情况(链状树)
- 无递归栈溢出风险
- 面试标准满分写法
- 前序、后序都可以基于这个模板改
七、总结(背会这 4 句话)
- 一路向左,全部入栈
- 走到最左,弹出栈顶
- 访问节点(中序位置)
- 转向右子树