题目:
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
思路:
等同于144题来思考,但是栈的操作要做些许的变化。
根据后序遍历的“左右中”顺序,中间节点应当先入栈,然后考虑中间节点是否包含的子节点,如果有子节点,则先入栈右子节点,再入栈左子节点;如果中间节点不包含子节点(叶节点),则直接pop出该节点,并将该节点的val写入结果中。
但是直接这样做会遇到一个问题,如示例中所给的二叉树,当迭代到最后一层时,我们的栈中从底到顶应当依次是:1,2,3。那么首先判断最顶的值:3。该节点为叶子节点,直接将3打印出来并将其pop掉。下一次迭代的节点为2,如果按照上方的思路,这时候会判断2是否具有子节点,那么这时会回到构建整个栈的所经历的步骤,即陷入了一个死循环,因为原本2的左子节点刚刚已经遍历过一次了,但是算法上并没有进行判断,因此原本的思路会继续将3压入栈中。
因此我们需要增加一个新的变量pre,pre的作用是记录算法上一次处理的节点,如果上一次处理的节点是当前处理的节点的子节点,那么必然可以断定,当前节点的两个子节点都已经遍历完毕,那么直接将当前节点弹出并打印即可。
代码:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null)
return result;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
if (root.right != null)
stack.push(root.right);
if (root.left != null)
stack.push(root.left);
TreeNode pre = root;
while (!stack.empty()) {
TreeNode temp = stack.peek();
if (pre != temp.left && pre != temp.right) {
if (temp.left == null && temp.right == null) {
temp = stack.pop();
result.add(temp.val);
} else {
if (temp.right != null)
stack.push(temp.right);
if (temp.left != null)
stack.push(temp.left);
}
}else {
temp = stack.pop();
result.add(temp.val);
}
pre = temp;
}
return result;
}
}