Leetcode#145 Binary Tree Postorder Traversal
递归写法谁都会,看看非递归写法。
对于二叉树的前序和中序遍历的非递归写法都很简单,只需要一个最普通的栈即可实现,唯独后续遍历有点麻烦,如果不借助额外变量没法记住究竟遍历了几个儿子。所以,最直接的想法就是在栈中记录到底遍历了几个儿子。
代码:
1 vector<int> postorderTraversal(TreeNode *root) { 2 vector<int> path; 3 stack<pair<TreeNode *, int> > st; 4 5 st.push(pair<TreeNode *, int>(root, 0)); 6 while (!st.empty()) { 7 pair<TreeNode *, int> top = st.top(); 8 st.pop(); 9 10 if (!top.first) 11 continue; 12 13 if (top.second == 0) { 14 top.second = 1; 15 st.push(top); 16 st.push(pair<TreeNode *, int>(top.first->left, 0)); 17 } 18 else if (top.second == 1) { 19 top.second = 2; 20 st.push(top); 21 st.push(pair<TreeNode *, int>(top.first->right, 0)); 22 } 23 else if (top.second == 2) { 24 path.push_back(top.first->val); 25 } 26 } 27 28 return path; 29 }
另外还有一种技巧性比较强的写法,只使用普通的栈就可以做到。利用到了一个后续遍历的特点,即:
后续遍历序列中,父节点前面一定紧挨着他的儿子节点(如果有的话)
所以,额外保存一个prev变量代表前一个遍历的节点,就可以识别出上面的情况。如果prev节点是当前节点的儿子节点(或者当前节点没有儿子),说明当前节点的儿子节点都遍历过了,可以遍历父节点了。
如何更新维护prev呢?当一个节点输出后,将prev置为这个节点,这是因为如果prev是后续遍历序列中的前一个节点,那么这个prev节点必须是已经被输出的节点。
代码如下:
1 vector<int> postorderTraversal(TreeNode *root) { 2 vector<int> path; 3 stack<TreeNode *> st; 4 TreeNode *prev = NULL; 5 6 st.push(root); 7 while (!st.empty()) { 8 TreeNode *node = st.top(); 9 10 if (!node) 11 st.pop(); 12 else if ((!node->left && !node->right) 13 || (prev && (node->left == prev || node->right == prev))) { 14 path.push_back(node->val); 15 st.pop(); 16 prev = node; 17 } 18 else { 19 st.push(node->right); 20 st.push(node->left); 21 } 22 } 23 24 return path; 25 }
也就短了几行而已。。