LeetCode 145:Binary Tree Postorder Traversal 解题与思考

来源:互联网 发布:数据库范式经典例题 编辑:程序博客网 时间:2024/06/01 09:30

LeetCode 145:Binary Tree Postorder Traversal 解题与思考

[原题链接]

题目描述

就是非递归的二叉树后续遍历

思路

通常来讲,将递归变为循环,都会想到用栈来模拟递归的过程;本题也不例外,只是需要考虑何时入栈何时出栈。

假设我们访问到一个节点,此时它的左右子树未访问;我们按照后序遍历的顺序,先访问左子节点,此时我们应该将当前节点压栈,因为在将左子树访问完毕之后,我们需要通过当前节点去访问右子树。

而在访问右子树之前,是否需要将这个节点出栈?答案是否定的:因为根据后续遍历的顺序,根节点是最后访问的。这个问题在另外两个遍历中的答案会和本题中答案不同,原因也是和自身的遍历顺序有关。

这个时候,我们不难得出一个算法:每次访问节点,将当前节点压栈,假如左节点不为空,则访问左节点;当左节点为空时,访问右节点;当两个节点都为空时,访问当前节点,然后将当前节点出栈。

而这个时候,我们需要判断左右节点是否都已经遍历过。注意到后续遍历的顺序,访问当前节点之前的那个节点,一定是该节点的右子节点。所以我们只需要判断上个访问的是否为该节点的右子节点,就能够判断是要访问右子树还是访问当前节点。

算法

前期准备:一个节点栈,一个答案数组

1、对于一个节点,将当前节点入栈,将当前节点设为其左子节点;
2、假如当前节点为空,若

  • 栈顶的点有右子树
  • 上一个被输出的节点不是该栈顶节点的右节点

倘若两条都符合,则将当前节点设置为栈顶节点的右节点

3、假如两条中有一条不符合,则栈顶节点一定是如下三种之一

  • 该节点左子树已经遍历完,且无右子树
  • 该节点右子树已经遍历完成
  • 该节点为叶子节点

将该节点假如答案数组中,并将上一个被输出的节点设为栈顶节点,然后将该节点出栈

代码

#include <iostream>#include <vector>#include <stack>class Solution {public:    vector<int> postorderTraversal(TreeNode* root) {        TreeNode *nowNode = root;        TreeNode *lastNode = NULL;        vector<int> result;        stack<TreeNode*> treeStack;        while ( nowNode || !treeStack.empty()) {            if ( nowNode ) {                treeStack.push(nowNode);                //lastNode = nowNode;                nowNode = nowNode->left;            }            else {                TreeNode *topNode = treeStack.top();                if ( topNode->right && lastNode != topNode->right ) {                    nowNode = topNode->right;                }                else {                    result.push_back(topNode->val);                    lastNode = topNode;                    treeStack.pop();                }            }        }        return result;    }};

思考

和前序、中序遍历不同的地方,需要考虑当前节点的右子树是否已经遍历过,否则会出现死循环(一直遍历右子树)