今天在刷Leetcode的二叉树卡片,首先碰到的就是二叉树的三种遍历方法,递归方法很简单,但是要求用迭代的方法来写的话就没那么容易了,在题解区里看到了一个大神的模板化迭代写法,非常有新意,于是在这里写点自己的理解
原文链接如下:
理论上来说,所有递归的算法都是可以用非递归来实现的,因为递归本身就是操作系统调用栈来保存函数的入口地址,遇到return之后返回到入口,因此用非递归方法写递归程序最核心的部分就是
1. 如何“保护现场”,在二叉树的遍历这里,原答案用到了一个nullptr空指针来保存当前访问但又不输出的那个节点(下面代码中的temp节点),也就是说,第二次遇到同一个节点的时候,意味着这个节点的前驱已经遍历过了,因此可以放心大胆地输出当前节点的value
2. 由于栈是FILO先进后出的结构,这就跟递归的顺序要相反,也就是说我们正常后序遍历的顺序是 left->right->mid,在栈这里就要mid->right->left的顺序入栈,出栈的时候才能按照正常递归的顺序
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
if(!root) return {};
vector<int>ans;
stack<TreeNode*>mystack; //用栈来保存遍历的节点
mystack.push(root);
while(!mystack.empty())
{
auto temp = mystack.top();
mystack.pop();
if(temp)
{
mystack.push(temp); //此题为后序遍历,因此入栈顺序要反过来,为中->左->右
mystack.push(nullptr);
if(temp->right) mystack.push(temp->right);
if(temp->left) mystack.push(temp->left);
}
else
{
ans.push_back(mystack.top()->val);
mystack.pop();
}
}
return ans;
}
};
上面是本人参照链接自己写的后序遍历的一个案例,先序遍历和中序遍历只需要将if(temp)里的入栈顺序作相应调整即可
另外此类题还有官方题解提到的莫里斯遍历,核心的部分也是确认当前节点的前驱是否已遍历,实现O(1)的空间复杂度,这里先占个坑,后面自己看懂了再来写感想