【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
先大概过一遍,心里有数。