先來看一下遞歸版的後序遍歷是怎麼寫的post
void dfs(TreeNode *root){ if(root==NULL) return ; dfs(root->left);//左節點 dfs(root->right);//右節點 cout<<roo->val<<endl;//訪問 }
能夠看到,對於root,咱們老是先訪問root的left兒子,right兒子,而後再訪問root,也就是說,咱們第三次看到root時候再對它進行訪問。spa
非遞歸的思想實際上是同樣的,當咱們第一次遇到root的時候,若是有左兒子,先將root擱置,而後去訪問它的左兒子,再遇到root的時候再將它擱置,去訪問它的右兒子,再三次遇到rootd的時候,訪問root,所謂擱置,就是將該節點放到stack中,當某一個之路訪問完畢後,也就是遇到NULL節點時,從stack中取出以前每訪問的節點,而後再接着上次訪問。code
記錄某個節點出現的次數,咱們能夠借用map。blog
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是否等於該節點的右兒子便可。io
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; } };