N 叉树的后序遍历(递归+迭代)

一、递归实现(简单)

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;
    }
};
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值