代码随想录算法训练营第16天|二叉树前中后序迭代法遍历
递归的本质就是每一次调用时将此次参数压入栈中,在递归返回值再将参数弹出。
因此,可以使用栈来实现前中后序的迭代法遍历。
1、前序遍历-迭代法
写起来难度不大,但是主要是为空时的判断都没考虑到。
代码
犯错:
- 两个错误都犯在了空指针的地方。需要好好反思一下
- stack的用法不太熟练
vector<int> preorderTraversal(TreeNode* root) {
//法2 迭代
vector<int> res;
stack<TreeNode*> s;
//注意这里若整个树为空!!
if(root == NULL)
return res;
s.push(root);
while(!s.empty()){
TreeNode* top;
top = s.top();
s.pop();
res.push_back(top->val);
//注意这里要判断是否空!!
if(top->right)
s.push(top->right);
if(top->left)
s.push(top->left);
}
return res;
}
2、中序遍历-迭代法
不能够直接拿前序遍历的迭代法改一改。原因是前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,所以刚刚才能写出相对简洁的代码,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。
而中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的
因此,使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
示意图:
代码:
注意理解思路,访问到最底层,pop时访问元素,深入右子树。
vector<int> inorderTraversal(TreeNode* root) {
//法2 迭代法
vector<int> res;
stack<TreeNode*> s;
TreeNode* cur = root;
while(cur!=NULL || !s.empty()){
//访问到最底层
if(cur!=NULL){
s.push(cur);
cur = cur->left;
}
//pop时访问元素,并继续深入右子树
else{
//访问元素
cur = s.top();
s.pop();
res.push_back(cur->val);
//深入右子树
cur = cur->right;
}
}
return res;
}
3、后序遍历-迭代法
思路:先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了。
反转,甚妙!!!
代码
犯错:忘记pop了,笨…
vector<int> postorderTraversal(TreeNode* root) {
//法1 递归
// vector<int> res;
// postorder(root, res);
// return res;
//法2 迭代,反转前序遍历
vector<int> res;
stack<TreeNode*> s;
if(root == NULL)
return res;
s.push(root);
while(!s.empty()){
TreeNode* top = s.top();
s.pop();//忘记pop了
res.push_back(top->val);
//这里调换了前序遍历的顺序
if(top->left != NULL)
s.push(top->left);
if(top->right != NULL)
s.push(top->right);
}
//反转
reverse(res.begin(), res.end());
return res;
}
总结
- 前中后序迭代法
- 后序的迭代可以用前序的迭代修改后反转得到——未曾设想的思路,很神奇。
- stack的用法。push(), top(), pop(), empty()
- 反转数组reverse()函数