Binary Tree Postorder Traversal

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?

思路:recursion version:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        postorderTraversalHelper(root, list);
        return list;
    }
    
    public void postorderTraversalHelper(TreeNode node, List<Integer> list) {
        if(node == null) return;
        postorderTraversalHelper(node.left, list);
        postorderTraversalHelper(node.right, list);
        list.add(node.val);
    }
}

Iterative version:

思路:依照并改写pre-order travel;

Pre-order is: current, left, right;

our goal is: left, right, current.

we can do: current, right, left.

最后需要反过来记录,那么就是用LinkedList 去addFirst就可以了。

犯错点:声明的时候,需要用LinkedList<Integer> list = new LinkedList<>();

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        LinkedList<Integer> list = new LinkedList<Integer>();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root);
        // left, right, current;
        // we can do preorder: current, left, right; 
        // we can do either: current, right, left; 
        // 所以如果我们逆序加result,也就是addFirst(val),那么就是 left, right, current;
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            list.addFirst(node.val);
            if(node.left != null) {
                stack.push(node.left);
            }
            if(node.right != null) {
                stack.push(node.right);
            }
        }
        return list;
    }
}

Morris travel: Space O(1) , Time O(n);
http://www.cnblogs.com/AnnieKim/archive/2013/06/15/morristraversal.html

后续遍历稍显复杂,需要建立一个临时节点dump,令其左孩子是root。并且还需要一个子过程,就是倒序输出某两个节点之间路径上的各个节点。

步骤:

当前节点设置为临时节点dump。

1. 如果当前节点的左孩子为空,则将其右孩子作为当前节点。

2. 如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点。

   a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点。当前节点更新为当前节点的左孩子。

   b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空。倒序输出从当前节点的左孩子到该前驱节点这条路径上的所有节点。当前节点更新为当前节点的右孩子。

3. 重复以上1、2直到当前节点为空。

在这里,我们需要创建一个临时的根节点dummy,把它的左孩子设为树的根root。同时还需要一个subroutine来倒序输出一条右孩子路径上的结点。跟迭代法一样我们需要维护cur指针和pre指针来追溯访问的结点。具体步骤是重复以下两步直到结点为空:
1. 如果cur指针的左孩子为空,那么cur设为其右孩子。
2. 否则,在cur的左子树中找到中序遍历下的前驱结点pre(其实就是左子树的最右结点)。接下来分两种子情况:
(1)如果pre没有右孩子,那么将他的右孩子接到cur。将cur更新为它的左孩子。
(2)如果pre的右孩子已经接到cur上了,说明这已经是回溯访问了,可以处理访问右孩子了,倒序输出cur左孩子到pre这条路径上的所有结点,并把pre的右孩子重新设为空(结点已经访问过了,还原现场)。最后将cur更新为cur的右孩子。
空间复杂度同样是O(1),而时间复杂度也还是O(n),倒序输出的过程只是加大了常数系数,并没有影响到时间的量级。如果对这个复杂度结果不是很熟悉的朋友,可以先看看Binary Tree Inorder Traversal中的分析,在那个帖子中讲得比较详细。
起始,理解了算法,代码都好写;按照图来就行了。

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        if(root == null) return list;
        
        //Morris postorder travel;
        TreeNode dummy = new TreeNode(0);
        dummy.left = root;
        TreeNode cur = dummy;
        TreeNode pre = null;
        
        while(cur!=null){
             pre = cur.left;
            if(pre==null){
                cur = cur.right;
            }else{
                while(pre.right!=null && pre.right != cur){
                    pre = pre.right;
                }
                
                if(pre.right == null){
                    pre.right = cur;
                    cur = cur.left;
                }else{
                    reverse(cur.left,pre);
                    TreeNode node = pre;
                    while(node!=cur.left){
                        list.add(node.val);
                        node = node.right;
                    }
                    list.add(node.val);
                    reverse(pre,cur.left);
                    pre.right = null;
                    cur = cur.right;
                }
            }
        }
        return list;
    }
    
    public void reverse(TreeNode start, TreeNode end){
        if(start == end){
            return;
        }
        
        TreeNode pre = start;
        TreeNode cur = start.right;
        TreeNode next;
        while(pre!=end){
            next = cur.right;
            cur.right = pre;
            pre = cur;
            cur = next;
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值