先来看一下递归版的后序遍历是怎么写的
void dfs(TreeNode *root){ if(root==NULL) return ; dfs(root->left);//左节点 dfs(root->right);//右节点 cout<<roo->val<<endl;//访问 }
可以看到,对于root,我们总是先访问root的left儿子,right儿子,然后再访问root,也就是说,我们第三次看到root时候再对它进行访问。
非递归的思想其实是一样的,当我们第一次遇到root的时候,如果有左儿子,先将root搁置,然后去访问它的左儿子,再遇到root的时候再将它搁置,去访问它的右儿子,再三次遇到rootd的时候,访问root,所谓搁置,就是将该节点放到stack中,当某一个之路访问完毕后,也就是遇到NULL节点时,从stack中取出之前每访问的节点,然后再接着上次访问。
记录某个节点出现的次数,我们可以借用map。
code:
class Solution { vector<int> ans; public: stack<TreeNode*>st; map<TreeNode*,int >mp; vector<int> postorderTraversal(TreeNode* root) { mp.clear(); if(!root) return ans; TreeNode* mark=NULL; while(root||st.size()){ if(root){//第一次遇到root,访问它的左儿子 st.push(root); mp[root]++; root=root->left; } else { while(st.size()){ TreeNode* p=st.top(); st.pop(); if(mp[p]==2||p->right==NULL){//如果说第三次遇到p,或者说该节点没有右节点,那么可以直接访问 ans.push_back(p->val); } else {//说明第二次遇到右儿子,访问右节点 mp[p]++; st.push(p); root=p->right; break; } } } } return ans; } };
除了用map记录外,还有一个十分巧妙的方法,如果说我们这次对root进行了访问,那么上次是对谁访问的?,一定是root->right,所以我们可以再访问root的同时对root记录一下,然后下次判断该节点是否可以访问的时候直接判断mark是否等于该节点的右儿子即可。
class Solution { vector<int> ans; public: stack<TreeNode*>st; vector<int> postorderTraversal(TreeNode* root) { mp.clear(); if(!root) return ans; TreeNode* mark=NULL; while(root||st.size()){ if(root){ st.push(root); root=root->left; } else { while(st.size()){ TreeNode* p=st.top(); st.pop(); if(p->right==mark||p->right==NULL){ ans.push_back(p->val); mark=p; } else { st.push(p); root=p->right; break; } } } } return ans; } };