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