• 【LeetCode】二叉树的深度优先遍历(前、中、后)


    (一)二叉树的前序遍历

    题目:144. 二叉树的前序遍历

    题目描述:给定一个二叉树,返回它的 前序 遍历(根左右)。

    示例:

    输入: [1,null,2,3]  
       1
        
         2
        /
       3 
    
    输出: [1,2,3]
    

    解题思路:

      从二叉树根结点开始,沿左子树一直走到末端(左孩子为空)为止,在走的过程中,访问所遇结点,并依次把所遇结点进栈,当左子树为空时,从栈顶退出某结点,并将指针指向该结点的右孩子。如此重复,直到栈为空或指针为空为止。

    代码实现:

    //方法一:递归,根左右
    class Solution {
        public List<Integer> preorderTraversal(TreeNode root) {
            List<Integer> res=new ArrayList<>();
            preorderTraversal(root,res);
            return res;
        }
        public void preorderTraversal(TreeNode root,List<Integer> res){
            if(root==null)
                return ;
            res.add(root.val);
            preorderTraversal(root.left,res);
            preorderTraversal(root.right,res);
        }
    }
    //方法二:非递归方法
    class Solution {
        public List<Integer> preorderTraversal(TreeNode root) {
            List<Integer> res=new ArrayList<>();
            if(root==null)
                return res;
            
            Stack<TreeNode> stack=new Stack<>();
            TreeNode p=root;
    
            while(p!=null || !stack.isEmpty()){
                while(p!=null){
                    res.add(p.val);
                    stack.push(p);  //进栈
                    p=p.left;   //进入左子树
                }
                p=stack.pop();  //退栈
                p=p.right;
            }
    
            return res;
        }
    }
    

    (二)二叉树的中序遍历

    题目:94. 二叉树的中序遍历

    题目描述:给定一个二叉树,返回它的中序 遍历。

    示例:

    输入: [1,null,2,3]
       1
        
         2
        /
       3
    
    输出: [1,3,2]
    

    解题思路:

      从二叉树根结点开始,沿左子树一直走到末端(左孩子为空)为止,在走的过程中,把依次遇到的结点进栈,待左子树为空时,从栈中退出结点并访问,并将指针指向该结点的右孩子。如此重复,直到栈为空或指针为空为止。

    代码实现:

    //方法一:递归,左根右
    class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> res = new ArrayList<>();
            inorderTraversal(root,res);
            return res;
        }
        public void inorderTraversal(TreeNode root,List<Integer> res){
            if(root==null)
                return ;
            inorderTraversal(root.left,res);
            res.add(root.val);
            inorderTraversal(root.right,res);
        }
    }
    //方法二:非递归,迭代
    class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> res=new ArrayList<>();
            if(root==null)
                return res;
            
            Stack<TreeNode> stack=new Stack<>();
            TreeNode p=root;
    
            while(p!=null ||  !stack.isEmpty()){
                while(p!=null){
                    stack.push(p);  //进栈
                    p=p.left;   //向左
                }
                p=stack.pop();  //弹栈
                res.add(p.val);  //访问
                p=p.right;   //向右
            }
    
            return res;
        }
    }
    

    (三)二叉树的后序遍历

    题目:145. 二叉树的后序遍历

    题目描述:给定一个二叉树,返回它的 后序 遍历。

    示例:

    输入: [1,null,2,3]  
       1
        
         2
        /
       3 
    
    输出: [3,2,1]
    

    解题思路:

      在后序遍历中,当搜索指针指向某一个结点时,不能马上进行访问,而先要遍历左子树,所以此结点应先进栈保存,当遍历完它的左子树后,再次回到该结点,还不能访问它,还需先遍历其右子树,所以该结点还必须再次进栈,只有等它的右子树遍历完后,再次退栈时,才能访问该结点。为了区分同一结点的两次进栈,引入一个栈次数的标志,一个元素第一次进栈标志为0,第二次进栈标志为1,并将标志存入另一个栈中,当从标志栈中退出的元素为1时,访问结点。

    代码实现:

    //方法一:递归,左右根
    class Solution {
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> res=new ArrayList<>();
            if(root==null)
                return res;
            postorderTraversal(root,res);
            return res;
        }
        public void postorderTraversal(TreeNode root,List<Integer> res){
            if(root==null)
                return;
            postorderTraversal(root.left,res);
            postorderTraversal(root.right,res);
            res.add(root.val);
        }
    }
    
    //方法二:非递归
    class Solution {
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> res=new ArrayList<>();
            if(root==null)
                return res;
            
            Stack<TreeNode> stack1=new Stack<>(); //栈1存放结点
            Stack<Integer> stack2=new Stack<>(); //栈2存放进栈次数的标志
            TreeNode p=root;
    
            do{
                while(p!=null){
                    stack1.push(p);
                    stack2.push(0);
                    p=p.left;
                }
    
                if(!stack1.isEmpty()){
                    int num=stack2.pop();
                    p=stack1.pop();
                    if(num==0){
                        stack1.push(p);
                        stack2.push(1);
                        p=p.right;
                    }
                    else{
                        res.add(p.val);
                        p=null;
                    }
                }
            }while(!stack1.isEmpty());
    
            return res;
        }
    }
    

    总结:

      二叉树的深度优先遍历是二叉树题目中最基本的算法,很多算法都基于深度优先遍历进行变形,其中递归解法相对很简单,特别是对非递归的迭代方法,基于栈是基础,要着重理解。

  • 相关阅读:
    飞入飞出效果
    【JSOI 2008】星球大战 Starwar
    POJ 1094 Sorting It All Out
    POJ 2728 Desert King
    【ZJOI 2008】树的统计 Count
    【SCOI 2009】生日快乐
    POJ 3580 SuperMemo
    POJ 1639 Picnic Planning
    POJ 2976 Dropping Tests
    SPOJ QTREE
  • 原文地址:https://www.cnblogs.com/gzshan/p/12634231.html
Copyright © 2020-2023  润新知