zoukankan      html  css  js  c++  java
  • 【Binary Tree Post order Traversal】cpp

    题目:

    Given a binary tree, return the postorder traversal of its nodes' values.

    For example:
    Given binary tree {1,#,2,3},

       1
        
         2
        /
       3
    

    return [3,2,1].

    Note: Recursive solution is trivial, could you do it iteratively?

    代码:

    stack 1:

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode* root) {
                vector<int> ret;
                if (!root) return ret;
                stack<TreeNode *> sta;
                sta.push(root);
                while ( !sta.empty() ){
                    TreeNode *tmp = sta.top();
                    sta.pop();
                    if ( tmp->left || tmp->right ){    
                        TreeNode *l = tmp->left, *r = tmp->right;
                        tmp->left = tmp->right = NULL;
                        sta.push(tmp);
                        if (r) sta.push(r);
                        if (l) sta.push(l);
                    }
                    else{
                        ret.push_back(tmp->val);
                    }
                }
                return ret;
        }
    };

    stack 2:

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode* root) {
                vector<int> ret;
                stack<TreeNode *> sta;
                TreeNode *curr = root;
                while ( !sta.empty() || curr )
                {
                    if (curr)
                    {
                        sta.push(curr);
                        curr = curr->left;
                    }
                    else
                    {
                        curr = sta.top();
                        if ( !curr->right )
                        {
                            ret.push_back(curr->val);
                            sta.pop();
                            curr = NULL;
                        }
                        else
                        {
                            curr = curr->right;
                            sta.top()->right = NULL;
                        }
                    }
                }
                return ret;
        }
    };

    tips:

    上述两个代码都是基于stack的操作完成的后序遍历二叉树。

    个人更喜欢stack 1的风格,思路如下:

    0. 先压root入栈

    1. 栈顶元素出栈

    2. 如果其左右都为空:则可以直接推入ret中

        否则:先将这个节点的left和right保存下来;再将这个节点与其子分支剪断(right left都置为NULL);再按照tmp, right, left的顺序入栈。

    循环1~2,直到栈空,则后序遍历完成

    网上一些答案很多都是基于stack 2这种方法,维护一个当前指针curr。

    这个思路就是一条道走到黑的思路(DFS深搜)

    1. curr不为NULL,则一直沿着left的方向走,直到走到NULL

    2. 只要curr为NULL,则一定是栈顶元素的left已经没有了(走到头了),则需要判断栈顶元素的right是否为NULL;

      如果为NULL,则证明栈顶元素的left和right都访问过了,栈顶元素的val可以推入ret;

      如果不为NULL,则证明其right还得遍历。这个时候,需要完成两件事情:

        a. curr向right走

        b. 栈顶元素的right置为空(标记再次访问栈顶元素,其right已经再curr= curr->right的带领下处理过了)

    其实stack 2的思路跟stack 1类似,都是需要判断栈顶元素的left和right是否都NULL,再决定栈顶元素的val是否推入ret。

    ==========================================

    stack1和2的方法都在遍历之后对原有的数据结构损坏了(这显然是不合理的),因此改写了如下的代码,不递归不损坏原有数据结构

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode* root) {
                vector<int> ret;
                stack<TreeNode *> sta;
                TreeNode *curr = root;
                std::map<TreeNode *, bool> r_visited;
                while ( !sta.empty() || curr )
                {
                    if (curr)
                    {
                        sta.push(curr);
                        curr = curr->left;
                    }
                    else
                    {
                        curr = sta.top();
                        if ( !curr->right || r_visited.find(curr)!=r_visited.end()?r_visited[curr]:false )
                        {
                            ret.push_back(curr->val);
                            sta.pop();
                            curr = NULL;
                        }
                        else
                        {
                            curr = curr->right;
                            r_visited[sta.top()] = true;
                        }
                    }
                }
                return ret;
        }
    };

    tips:

    之前如果curr->right访问过了,就直接sta.top()->right=NULL了,显然破坏了原有的数据结构。

    这里用一个hashmap来保存访问过TreeNode的right是否被访问了。多了一个hashmap,但保住了原有数据结构。

    =======================================================

    第二次过这道题,就看看非递归的写法。找到了下面的一个blog:http://noalgo.info/832.html

    用类似先序遍历的代码,再做一次翻转,就得到了后续遍历的结果。

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode* root) {
                vector<int> ret;
                stack<TreeNode*> sta;
                if ( root ) sta.push(root);
                while ( !sta.empty() )
                {
                    TreeNode* tmp = sta.top();
                    sta.pop();
                    ret.push_back(tmp->val);
                    if ( tmp->left ) sta.push(tmp->left);
                    if ( tmp->right ) sta.push(tmp->right);
                }
                std::reverse(ret.begin(), ret.end());
                return ret;
        }
    };

     后续遍历的顺序是:left right mid

    因此,只要按照 mid right left的顺序遍历一次 再做reverse就可以了。

    这个思路很巧妙。

    ========================================

    做了这道题 突然想到了二叉树最小公共祖先,搜了一下http://blog.csdn.net/luckyxiaoqiang/article/details/7518888

    先大概过一遍,心里有数。

  • 相关阅读:
    Javascript获取本周,本月,本季,本年,上月,上周,上季,去年,上二周,上二月
    SQL SERVER 2008 评估期已过的解决办法
    习惯那些“小事”
    Oracle 测试语句
    整理js常用按键相关代码
    .NET 学习笔记
    lamda表达式学习
    使用Html.DropDownList
    ibatis
    MyBatis
  • 原文地址:https://www.cnblogs.com/xbf9xbf/p/4501994.html
Copyright © 2011-2022 走看看