回覆列表
  • 1 # 使用者4210379170316

    1、遞迴法

    直接上程式碼:

    //recursion

    class Solution1 {

    public:

    vector<int> postorderTraversal(TreeNode* root) {

    vector<int> ret;

    postHelper(ret,root);

    return ret;

    }

    private:

    void postHelper(vector<int>& ret,TreeNode* root)

    {

    if(root==NULL)return;

    postHelper(ret,root->left);

    postHelper(ret,root->right);

    ret.push_back(root->val);

    }

    };

    2、迭代法

    迭代法使用一個棧來儲存當前不需要訪問的節點。不過,不同於中序遍歷與前序遍歷,在後序遍歷中每一個節點需要一個標誌位,來標識當前節點的左右子樹是否被訪問。因為在後序遍歷中,只有一個節點的左右子樹被訪問後它才能被訪問。因此,壓入棧中的資料型別需要是一個pair<TreeNode*,int>,其中用1來表示當前節點的左右子樹正被訪問,當再次訪問到此節點時可以訪問此節點;用0表示當前節點的左右子樹未被訪問,再次訪問到此節點時需要首先訪問此節點的左右子樹。程式碼如下:

    //iteration

    class Solution1 {

    public:

    vector<int> postorderTraversal(TreeNode* root) {

    vector<int> ret;

    if(root==NULL)return ret;

    stack<pair<TreeNode*,int>> st;

    st.push(make_pair(root,0));

    while(!st.empty())

    {

    TreeNode *curr=st.top().first;

    if(st.top().second==1)

    {

    ret.push_back(curr->val);

    st.pop();

    }

    else

    {

    st.top().second=1;

    if(curr->right)st.push(make_pair(curr->right,0));

    if(curr->left)st.push(make_pair(curr->left,0));

    }

    }

    return ret;

    }

    }

    3、迭代法:按照根、右、左的順序訪問然後取反

    這種方法就是按照根、右、左的順序訪問,然後將結果取反即可。後序遍歷的順序是左、右、根。這種方法就可以在前序遍歷的基礎上修改即可。程式碼如下:

    class Solution3 {

    public:

    vector<int> postorderTraversal(TreeNode* root) {

    vector<int> ret;

    if(root==NULL)return ret;

    stack<TreeNode*> st;

    st.push(root);

    while(!st.empty())

    {

    TreeNode *curr=st.top();

    st.pop();

    if(curr->left)st.push(curr->left);

    if(curr->right)st.push(curr->right);

    ret.push_back(curr->val);

    }

    reverse(ret.begin(),ret.end());

    return ret;

    }

    };

    在按照根、右、左的順序遍歷時,每個節點訪問一遍,最後將結果取反時,每個節點也訪問一遍,因此節點的總訪問次數和方法2相同。

    4、Morris方法

    後序遍歷的Morris方法思路比較難。但整體上還是一樣的,對原來的二叉樹的修改也是一樣的,不同的是訪問的順序。而在後序遍歷中,訪問時比較麻煩。下面是整個演算法的工作過程;

    首先建立一個臨時節點dump,令其左兒子是root。並且還需要一個子過程,就是倒序輸出某兩個節點之間路徑上的各個節點。

    步驟:

    當前節點設定為臨時節點dump。

    (1)如果當前節點的左兒子為空,則將其右兒子作為當前節點;

    (2)如果當前節點的左兒子非空,在當前節點的左子樹中找到當前節點在中序遍歷下的前驅節點;

    a) 如果前驅節點的右孩子為空,將它的右兒子設定為當前節點。當前節點更新為當前節點的左兒子;

    b) 如果前驅節點的右兒子為當前節點,將它的右孩子重新設為空。倒序輸出從當前節點的左兒子到該前驅節點這條路徑上的所有節點。當前節點更新為當前節點的右兒子;

    (3)重複以上(1)(2)直到當前節點為空。

    程式碼如下:

    //morris

    class Solution4 {

    public:

    vector<int> postorderTraversal(TreeNode* root) {

    vector<int> ret;

    TreeNode *dump=new TreeNode(0);

    dump->left=root;

    TreeNode *curr=dump;

    TreeNode *pre;

    while(curr)

    {

    if(curr->left==NULL)

    {

    curr=curr->right;

    }

    else

    {

    pre=curr->left;

    while(pre->right&&pre->right!=curr)

    pre=pre->right;

    if(pre->right==NULL)

    {

    pre->right=curr;

    curr=curr->left;

    }

    else

    {

    reverseAddNodes(curr->left,pre,ret);

    pre->right=NULL;

    curr=curr->right;

    }

    }

    }

    return ret;

    }

    private:

    void reverseAddNodes(TreeNode *begin,TreeNode *end,vector<int>& ret)

    {

    reverseNodes(begin,end);

    TreeNode *curr=end;

    while(true)

    {

    ret.push_back(curr->val);

    if(curr==begin)break;

    curr=curr->right;

    }

    reverseNodes(end,begin);

    }

    void reverseNodes(TreeNode *begin,TreeNode *end)

    {

    TreeNode *pre=begin;

    TreeNode *curr=pre->right;

    TreeNode *post;

    while(pre!=end)

    {

    post=curr->right;

    curr->right=pre;

    pre=curr;

    curr=post;

    }

    }

    }

  • 中秋節和大豐收的關聯?
  • 《海賊王》尾田說路飛夥伴還缺一人,你認為誰才是草帽團的第十個夥伴?為什麼?