二叉树的前中后序遍历一般都有两种方法,递归的和迭代的。
一、递归
递归的方法比较好理解,但是对于我个人来说,在本科刷题、研究生刷题以及当前,很久不做再次去做的时候会因为同一个原因卡壳:就是题干给出的函数形式中,遍历所得的结果以函数返回值表示时,我会反应不过来,因为迭代的传参特点。
总结多次失败经验,现在看到这种情况,应该首先意识到,如果使用函数返回值传参,能够正确存放迭代的结果吗?如果可以,那么就可以使用,如果不可以,那么就不要囿于题干所给函数,重新定义一个引用传参的函数即可。
中序遍历递归比较简单,定义一个引用传参的函数即可简单解决:
/**
* 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> inorderTraversal(TreeNode* root)
{
vector<int> res;
inorderTraversal_(root,res);
return res;
}
void inorderTraversal_(TreeNode* root,vector<int> &res)
{
if(!root)
{
return;
}
if(root->left)
{
inorderTraversal_(root->left,res);
}
res.push_back(root->val);
if(root->right)
{
inorderTraversal_(root->right,res);
}
}
};
如果不定义引用传参函数,直接使用给定的函数的话,就要考虑递归之后的结果值如何传递。
vector<int> inorderTraversal_ori(TreeNode* root)
{
vector<int> res;
if(!root)
{
return res;
}
vector<int> leftRes = inorderTraversal(root->left);
res.insert(res.end(),leftRes.begin(),leftRes.end());
res.push_back(root->val);
vector<int> rightRes = inorderTraversal(root->right);
res.insert(res.end(),rightRes.begin(),rightRes.end());
return res;
}
二、迭代法
迭代法需要考虑的非常全面,很多时候很多次自己都能想的大概,但是写出来总是有点问题导致不能通过。
这道题的迭代解法,我一开始想到的关键点是:
1)进栈完成之后,看看有没有左节点,有左节点就一直进栈;没有左节点了就出栈。
2)出栈完成之后(即根节点值已经保存下来了)看看该节点有没有右节点,有右节点就将该右节点进栈。
对比下面的这个正确解法,其实思路是对的,但是就是写出来就不对了。在很多细节上没有把握好。
分析下面的正确解法:
1)只要当前节点非空,就进栈。进栈之后指针指向左节点。--左节点一直进栈
2)如果当前节点为空了,那么说明【左节点不存在了】该返回到父节点了。此时父节点在栈里,弹出即可。
3)父节点即为中间节点,将其放入结果数组,然后找右节点。
4)回到第一步,找当前节点的左节点,如果找不到,那么当前节点即可作为中间节点
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> res;
if(!root)
{
return res;
}
stack<TreeNode*> s;
TreeNode* cur= root;
while(cur || !s.empty())
{
if(cur)
{
s.push(cur);
cur = cur->left;
}
else
{
cur = s.top();
res.push_back(cur->val);
s.pop();
cur = cur->right;
}
}
return res;
}
感觉还是一样,这个题目的大体思路是对的,但是总是写的不对。后面多做几次。