一、递归实现(简单)
void PostOrderHelp(Node* root, vector<int> &res)
{
for(auto child:root->children)
{
if(child!=nullptr)
{
PostOrderHelp(child,res);
}
}
res.push_back(root->val);
}
class Solution {
public:
vector<int> postorder(Node* root) {
vector<int> ans;
//递归写法
if(root!=nullptr)
PostOrderHelp(root,ans);
return ans;
}
};
二、迭代实现
数据结构:栈 哈希表
思路:从root节点向左下方向查找,当查找到最左下时,改变方向至当前节点的兄弟节点或者父节点。从新的点继续向左下访问。当该节点处于无子节点状态或从最后一个子节点访问返回时,输出该节点代表的值。用栈来辅助找兄弟节点、哈希表用来记录对于某个节点,当前访问到了其第几个子节点。
key: 对于一个顶点v,在向左下访问时有可能访问到,在改变访问方向,从下向上回溯过程中也可能会经过,因此,对于栈里面的顶点,需要去分辨出在当前情况下,是否需要向左下方向访问。在本代码中,通过设置nowpos==nullptr区分出两种情况。当一个顶点的所有子节点都访问完毕时需要不断向上回溯,去找到右边的最近的一个分支,即下一个要访问的分支。
代码:
class Solution {
public:
vector<int> postorder(Node* root) {
vector<int> ans;
unordered_map<Node *,int> cnt; //记录每个顶点分别已经入栈过多少个顶点了。
stack<Node *> st;
Node* nowpos;
if(root!=nullptr)
st.push(root);
nowpos=root;
while(!st.empty())
{
while(nowpos!=nullptr)
{
cout<<"1:"<<nowpos->val<<endl;
if(nowpos->children.size()>0)
{
cnt[nowpos]=0; //对cnt进行赋值
st.push(nowpos->children[0]);
nowpos=nowpos->children[0];
}
else
{
nowpos=nullptr;
}
}
//已访问至左下角,跳转至其兄弟节点or上层节点
nowpos=st.top();
cout<<"2:"<<nowpos->val<<endl;
if( cnt[nowpos]+1 < nowpos->children.size() )
{
cnt[nowpos]+=1;
st.push(nowpos->children[cnt[nowpos]]);
nowpos=nowpos->children[cnt[nowpos]];
}
else
{
ans.push_back(nowpos->val);
st.pop();
nowpos=nullptr; //用nowpos=nullptr标记了这是从下面返回来的点,这个时候就不用再进行左遍历了,否则会造成循环
}
}
return ans;
}
};
优化:
可以看到,上面的迭代方式,当在某个分支访问到最左下时,确定下一个要访问的点的步骤较为复杂,容易出错。已知对于一个节点,在后序遍历过程中,必然时从左到右依次访问每个子树,因此对于一个节点v,当第一次访问至v时可以将其所有子节点从右至左依次入栈,这样可以使得当第一个子树完全遍历后,通过取栈顶,自然地找到了下一个要访问的位置。当一个节点没有任何孩子节点时,则打印该节点、出栈、取栈顶元素继续向左下访问。
class Solution {
public:
vector<int> postorder(Node* root) {
vector<int> ans;
unordered_set<Node *> visited; //记录改顶点是否已经访问过(在回溯过程中用到)
stack<Node *> st;
Node* nowpos;
if(root!=nullptr)
st.push(root);
while(!st.empty())
{
nowpos=st.top();
if(0==nowpos->children.size() || visited.count(nowpos) )
{
ans.push_back(nowpos->val);
st.pop();
}
else
{
for(auto v=nowpos->children.rbegin(); v!= nowpos->children.rend();v++)
{
st.push(*v);
}
}
visited.insert(nowpos);
}
return ans;
}
};