树的遍历总结 (包括递归,非递归2种解法),轻松理解后序遍历

本文详细介绍了二叉树的前序、中序、后序遍历以及层次遍历的实现方法,并通过迭代和递归两种方式展示了如何在不同遍历顺序下访问树节点。同时,文章提供了具体的代码示例,帮助读者理解和实践这些核心算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考大神的神作:http://blog.youkuaiyun.com/fightforyourdream/article/details/16843303 

对于后序遍历,我们理解为将右节点为先的先序遍历翻转,会思考上简单很多,就是用右节点为先的先序遍历做,再用第二个栈进行翻转,就是后序遍历。

/*
     * 3. 前序遍历,中序遍历,后序遍历: preorderTraversalRec, preorderTraversal, inorderTraversalRec, postorderTraversalRec 
     * (https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2)
     * */
    public static void preorderTraversalRec(TreeNode root) {
        if (root == null) {
            return;
        }
        
        System.out.print(root.val + " ");
        preorderTraversalRec(root.left);
        preorderTraversalRec(root.right);
    }
    
    /*
     * 前序遍历,Iteration 算法. 把根节点存在stack中。
     * */
    public static void preorderTraversal(TreeNode root) {
        if (root == null) {
            return;
        }
        
        Stack s = new Stack();
        s.push(root);
        
        while (!s.isEmpty()) {
            TreeNode node = s.pop();
            System.out.print(node.val + " ");
            if (node.right != null) { //
                s.push(node.right);
            }
            
            // 我们需要先压入右节点,再压入左节点,这样就可以先弹出左节点。 
            if (node.left != null) {
                s.push(node.left);
            }                       
        }
    }
    
    /*
     * 中序遍历
     * */
    public static void inorderTraversalRec(TreeNode root) {
        if (root == null) {
            return;
        }
        
        inorderTraversalRec(root.left);
        System.out.print(root.val + " ");
        inorderTraversalRec(root.right);
    }
    
    /** 
     * 中序遍历迭代解法 ,用栈先把根节点的所有左孩子都添加到栈内, 
     * 然后输出栈顶元素,再处理栈顶元素的右子树 
     * http://www.youtube.com/watch?v=50v1sJkjxoc 
     *  
     * 还有一种方法能不用递归和栈,基于线索二叉树的方法,较麻烦以后补上 
     * http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/ 
     */  
    public static void inorderTraversal(TreeNode root) {
        if (root == null) {
            return;
        }
        
        Stack s = new Stack();
        
        TreeNode cur = root;
        
        while(true) {
            // 把当前节点的左节点都push到栈中.
            while (cur != null) {
                s.push(cur);
                cur = cur.left;
            }
            
            if (s.isEmpty()) {
                break;
            }
            
            // 因为此时已经没有左孩子了,所以输出栈顶元素 
            cur = s.pop();
            System.out.print(cur.val + " ");
            
            // 准备处理右子树  
            cur = cur.right;            
        }
    }
    
    // 后序遍历
    /*
     *      1  
           / \  
          2   3  
         / \   \  
        4   5   6
        
        if put into the stack directly, then it should be:
        1, 2, 4, 5, 3, 6 in the stack.
        when pop, it should be: 6, 3, 5, 4, 2, 1
        
        if I 
     * */
    
    public static void postorderTraversalRec(TreeNode root) {
        if (root == null) {
            return;
        }
        
        postorderTraversalRec(root.left);
        postorderTraversalRec(root.right);
        System.out.print(root.val + " ");
    }
    
    /** 
     *  后序遍历迭代解法 
     *  http://www.youtube.com/watch?v=hv-mJUs5mvU 
     *  http://blog.youkuaiyun.com/tang_jin2015/article/details/8545457
     *  从左到右的后序 与从右到左的前序的逆序是一样的,所以就简单喽! 哈哈
     *  用另外一个栈进行翻转即可喽 
     */ 
    public static void postorderTraversal(TreeNode root) {
        if (root == null) {
            return;
        }
        
        Stack s = new Stack();
        Stack out = new Stack();
        
        s.push(root);
        while(!s.isEmpty()) {
            TreeNode cur = s.pop();
            out.push(cur);
            
            if (cur.left != null) {
                s.push(cur.left);
            }
            if (cur.right != null) {
                s.push(cur.right);
            }
        }
        
        while(!out.isEmpty()) {
            System.out.print(out.pop().val + " ");
        }
    }
    
    /*
     * 分层遍历二叉树(按层次从上往下,从左往右)迭代 
     * 其实就是广度优先搜索,使用队列实现。队列初始化,将根节点压入队列。当队列不为空,进行如下操作:弹出一个节点 
     * ,访问,若左子节点或右子节点不为空,将其压入队列 
     * */
    public static void levelTraversal(TreeNode root) {
        if (root == null) {
            return;
        }
        
        Queue q = new LinkedList();
        q.offer(root);
        
        while (!q.isEmpty()) {
            TreeNode cur = q.poll();
            
            System.out.print(cur.val + " ");
            if (cur.left != null) {
                q.offer(cur.left);
            }
            if (cur.right != null) {
                q.offer(cur.right);
            }
        }
    }
    
    public static void levelTraversalRec(TreeNode root) {
        ArrayList> ret = new ArrayList>();
        levelTraversalVisit(root, 0, ret);
        System.out.println(ret);
    }
    
    /** 
     *  分层遍历二叉树(递归) 
     *  很少有人会用递归去做level traversal 
     *  基本思想是用一个大的ArrayList,里面包含了每一层的ArrayList。 
     *  大的ArrayList的size和level有关系 
     *   
     *  http://discuss.leetcode.com/questions/49/binary-tree-level-order-traversal#answer-container-2543 
     */  
    public static void levelTraversalVisit(TreeNode root, int level, ArrayList> ret) {
        if (root == null) {
            return;
        }
        
        // 如果ArrayList的层数不够用, 则新添加一层
        // when size = 3, level: 0, 1, 2
        if (level >= ret.size()) {
            ret.add(new ArrayList());
        }
        
        // visit 当前节点
        ret.get(level).add(root.val);
        
        // 将左子树, 右子树添加到对应的层。
        levelTraversalVisit(root.left, level + 1, ret);
        levelTraversalVisit(root.right, level + 1, ret);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值