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
原文地址:http://blog.csdn.net/elton_xiao/article/details/46386653