[Leetcode] Binary Tree Postorder Traversal
来源:互联网 发布:域名具有什么属性 编辑:程序博客网 时间:2024/05/16 00:40
题目:
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?
Leetcode上并没有这道题,但是由于和inorder类似,所以写上来。
思路:递归的做法非常简单,重点是如何用循环来做。
整体思路是利用一个堆栈去模拟递归的过程,问题是,如果完全按照递归的过程去做堆栈,那么对于栈顶的元素A需要将左子树压入堆栈,然后当左边的元素弹出堆栈后,再将右子树压入堆栈,最后弹出A。这样,元素A有三次成为栈顶的机会:第一次压入了左子树;第二压入右子树,第三次弹出,输出——递归的做法由于实际压入堆栈的是一个函数,很好的记录了当前状态(即进行到哪一步了);可是堆栈无法记录。
解决的办法有很多,第一种是修改node的结构,但这一次bool成员无法满足要求了,因为需要记录三种状态,一是没压左子树的,需要压入左子树,二是压完左子树的,那么压入右子树,三是压完右子树的,那么输出并弹出;因此,需要用一个int去记录;第二种是利用一个hashmap去存上述状态;另外还有用两个栈去实现的做法。
比较好的做法是,类似inorder遍历,设置current指针。但是现在的问题是,当A的左子树遍历完,A回到栈顶时并不能弹出,需要将右子树压入。这样,A有三次作为栈顶,而current指针只能帮助区分前两个状态,无法区分A是需要压入右子树还是需要输出并弹出。因此,需要另一个指针来帮助区分。具体做法是,利用另一个指针last_pop记录上一次弹出的元素,如果上一次弹出的元素是当前元素的右子节点,那么右子树已经被访问过了,可以输出跟节点并弹出堆栈;反之,将右子树压入堆栈。
这里引入了几个新的问题,第一个是current指针的赋值问题。inorder遍历的时候,我们的做法是当current指向null时,说明栈顶的元素的左子树已经遍历完了,需要输出,出栈,同时将current指针导向右边继续向左向下走。可是,在做postorder的时候,栈顶元素的右子树可能没被访问过,那么把current指针导向右边,但栈顶元素的右子树也可能已经访问过,这个时候,current指针应该指向哪里呢?
如果仔细观察inorder的算法,就可以发现,current指针的作用并不仅仅是指向当前要访问的节点这么简单,他的根本作用在于控制访问节点的方向——当current非空时,由上向下访问;反之,由下向上访问。就inorder遍历来说,当current向左向下走到头的时候,向上访问,栈顶的元素可以安全输出,然后将current指针导向右边,继续向下访问。现在就很容易理解postorder是如何运作的了:当current等于null时,向上访问到栈顶元素A,此时,如果A的右节点没有被访问过,那么将current指向这个节点继续向下访问,若果A的右节点已经被访问过了,那么我们将A输出,出栈后,需要继续向上访问,因此,current指针的值不会发生变化,依然是null.
第二个问题是右子节点的判断问题。path.top()->right != last_pop是一个关键的条件:如果上一个弹出的节点不是右子节点,那么右子树很可能没有被访问过。有没有其他的条件呢?假设只有这一个条件,那么考虑一种情况:一个节点A只有左子节点B,没有右子节点。当B弹出堆栈后,A变成了栈顶。这时显然A的右子节点为null,并不为刚弹出的B,于是将current指向右边。下一次循环时,又会进入这条判断语句,current被再次赋值为null,造成死循环。造成这个死循环的根本原因是,右子树没有被访问过,于是赋值current,希望向下继续访问,而current正好是null,引导向上访问,于是程序就永远的停在了这个地方。因此,还需要加另一个判断条件:path.top()->right != nullptr,利用这个条件,我们保证了只有当右子节点不为空时,才进入这条语句,引导current,向下访问,否则,低于这个节点的所有节点已被访问完毕,输出这个节点,出栈,继续向上访问。
class Solution {public: vector<int> postorderTraversal(TreeNode *root) { vector<int> result; if (root == nullptr) return result; stack<TreeNode*> path; TreeNode* current = root; TreeNode* last_pop = nullptr; while (!path.empty() || current != nullptr) { if (current != nullptr) { //keep pushing the left subtree path.push(current); current = current->left; } else { //until reach the end if (path.top()->right != nullptr && path.top()->right != last_pop) { //right subtree has not been touched current = path.top()->right; //redirect to its right tree } else { //right subtree has been touched last_pop = path.top(); path.pop(); result.push_back(last_pop->val); } } } return result; }};
总结:复杂度为O(n).
- LeetCode Binary Tree Postorder Traversal
- LeetCode:Binary Tree Postorder Traversal
- Leetcode: Binary Tree Postorder Traversal
- Leetcode: Binary Tree Postorder Traversal
- LeetCode:Binary Tree Postorder Traversal
- Leetcode Binary Tree Postorder Traversal
- [LeetCode]Binary Tree Postorder Traversal
- [LeetCode] Binary Tree Postorder Traversal
- leetcode Binary Tree Postorder Traversal
- 【LeetCode】Binary Tree Postorder Traversal
- LeetCode | Binary Tree Postorder Traversal
- Leetcode: Binary Tree Postorder Traversal
- Binary Tree Postorder Traversal - LeetCode
- LeetCode - Binary Tree Postorder Traversal
- [LeetCode]Binary Tree Postorder Traversal
- Binary Tree Postorder Traversal -- LeetCode
- [LeetCode]Binary Tree Postorder Traversal
- 【LeetCode】Binary Tree Postorder Traversal
- TRIZ系列-创新原理-16-部分或超额行动原理
- 全世界还有44亿人无法上网
- xcxbhgnxvc
- xcxbhgnxvc
- cnhcvnvhngvhnvgh
- [Leetcode] Binary Tree Postorder Traversal
- Kinect 和外包
- Xsolla和Crytek合作,对游戏战争前线推出全新支付方式
- C#编程指南——隐式类型和匿名类型
- php中的printf和c语言中的printf一样
- C语言程序设计<四>
- 备份基础之完全、增量与差异备份
- 网络基本功(一):细说网络传输
- java for特殊用法 数组排序 进制转换