码迷,mamicode.com
首页 > 其他好文 > 详细

Binary Tree Postorder Traversal -- leetcode

时间:2015-06-06 13:38:24      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:leetcode   postorder   后序遍历   

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?



算法一,用栈同时保存父结点和右孩子。

后续遍历,为:

访问左子树;访问右子树;访问根结点。

思考了一下递归的执行过程。

于是用栈保留 父结点,和右孩子结点在栈上。成对保存。

用一个pair,来成对保存父结点,和右孩子结点。

当栈顶元素的pair中second不空时,我们知道该结点的右子树还没有访问。则访问该右子树。同时将second置空。

如果该second为空,说明右子树已经访问完。则可访问当前结点。访问后可pop该结点。结束对该子树的访问。

此代码在leetcode上实际执行时间为4ms。


/**
 * 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> ans;
        stack<pair<TreeNode *, TreeNode*> > s;
        while (root || !s.empty()) {
            if (root) {
                while (root) {
                    s.push(make_pair(root, root->right));
                    root = root->left;
                }
            }
            else if (s.top().second) {
                root = s.top().second;
                s.top().second = NULL;
            }
            else {
                root = s.top().first;
                s.pop();
                ans.push_back(root->val);
                root = NULL;
            }
        }
        return ans;
    }
};



算法二,用栈无区别保存父结点和右孩子

算法一中,栈保存的pair,而不是树结点本身。

主要是为了解决一个问题。 当看到一个栈元素时,如何区别出该元素左右孩子是否已经访问过。

如果访问过,则可以访问该结点,并出栈。

如果没访问过,则需要访问该结点的左右子树,再访问该结点。


结点本身没有地方可以存储这个信息。如何解决这个问题呢?

我们知道后序遍历的特点是,左右子树访问后,才访问该结点。

更严格的说,是其“右”子树的根结点输出后,那么下一位该输出的就是该结点。

如果右子树不存在,则是“左”子树根结点输出后,下一位该输出的就是该结点。


此处,我们用一个变量last,记录上一次输出的结点。

如果上一次输出的为自己的右子树(或者左子树根结点)。则该结点可访问了。

否则该结点所代表的子树尚未访问过。



4ms

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ans;
        stack<TreeNode *> s;
        TreeNode *last = NULL;
        while (root || !s.empty()) {
            if (root) {
                while (root) {
                    s.push(root);
                    if (root->right)
                        s.push(root->right);
                    root = root->left;
                }
            }
            else {
                root = s.top();
                s.pop();
                if (!root->left && !root->right || 
                    last && (last == root->left || last == root->right)) {
                        ans.push_back(root->val);
                        last = root;
                        root = NULL;
                }
            }
        }
        return ans;
    }
};


算法三,中右左遍历,再反转。

算法一,算法二,如此麻烦的原因都在于,根结点是最后被访问。看到一个栈顶元素,需要有额外信息来确定,该结点是否可以访问了。

如果把遍历次数,与后续遍历反转过来。改成  中右左。 则省去了这个麻烦。 看到一个结点,先访问了就是了。

此算法就与前序遍历一样简单了。

先访问根结点;访问右子树;访问左子树。


由于右子树会先于左子树访问。故在子树可以不必入栈。则需要将左子树入栈保存。


由于遍历顺序与后序正相反,最后将结果反转一下。

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ans;
        stack<TreeNode *> lefts;
        while (root || !lefts.empty()) {
            if (root) {
                ans.push_back(root->val);
                if (root->left)
                    lefts.push(root->left);
                root = root->right;
            }
            else {
                root = lefts.top();
                lefts.pop();
            }
        }
        reverse(ans.begin(), ans.end());
        return ans;
    }
};


Binary Tree Postorder Traversal -- leetcode

标签:leetcode   postorder   后序遍历   

原文地址:http://blog.csdn.net/elton_xiao/article/details/46386653

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!