题目
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?
要求求二叉树后序遍历结果,且是非递归的算法。
解题思路
二叉树后序遍历是指根结点相对于左右子树节点的遍历顺序,后序遍历访问顺序是左子树、右子树根结点。对于这个题目有两种解法,第一种是方法是:用栈来存储待访问的结点,如果栈非空,弹出一个节点,对于这个结点,如果它的左子树和右子树均为空,则肯定输出该节点信息;如果左子树不为空但右子树为空,当左子树已经访问(这里的访问表示已经输出值),下一个访问的结点肯定就是该节点;如果左子树为空但右子树不为空,当右子树已经访问,下一个访问的结点肯定也是该节点;如果左子树右子树均不为空,访问顺序肯定就是左子树、右子树和该节点,所以如果右子树已经访问,则下一个访问的结点肯定也是该节点;对于其他情况,该节点右子树不为空,则右结点压栈,左子树不为空,则左结点压栈。因为栈的特殊性,所以压栈顺序是相反的。因此,当访问一个节点时,我们记录该节点,如果下次碰到该节点的父节点,就通过判断来访问父节点。于是,有了下面的代码(不清楚的建议手动模拟一下):
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<Integer>();
if (root == null) {
return list;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode preNode = null;
TreeNode curNode = null;
stack.push(root);
while (!stack.isEmpty()) {
curNode = stack.peek();
if ((curNode.left == null && curNode.right == null)
|| (preNode != null && (curNode.left == preNode || curNode.right == preNode))) {
preNode = curNode;
list.add(curNode.val);
stack.pop();
} else {
if (curNode.right != null) {
stack.push(curNode.right);
}
if (curNode.left != null) {
stack.push(curNode.left);
}
}
}
return list;
}
第二种思路可能更难想到,算法比较简单容易理解,对于后序遍历的左子树、右子树和根结点的顺序,逆向顺序就是根结点、右子树和左子树。因此,栈来存储待访问的结点,如果栈非空,弹出一个节点,对于这个结点,直接将它的值加入链表,如果左子树非空,左结点入栈;右子树非空,右结点入栈。遍历完毕,将链表反转返回即可。
public List<Integer> postorderTraversal2(TreeNode root) {
List<Integer> list = new ArrayList<Integer>();
if (root == null) {
return list;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode curNode = null;
stack.push(root);
while (!stack.isEmpty()) {
curNode = stack.pop();
list.add(curNode.val);
if (curNode.left != null) {
stack.push(curNode.left);
}
if (curNode.right != null) {
stack.push(curNode.right);
}
}
Collections.reverse(list);
return list;
}
对于上面两种算法,在leetcode里均通过,但第一种所用时间短一些。