• 【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;
        }
    }
    

    总结:

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

  • 相关阅读:
    Webpack的学习总结(1)
    mybatis-plus逻辑删除
    vscode编译调试C/C++多文件——linux(makefile)
    vscode配置调试C/C++程序——linux环境(命令行编译)
    shell编程题(二十二)
    shell编程题(二十三)
    shell编程题(二十一)
    shell编程题(二十)
    GTK开发视频播放器
    C语言实现LRU缓存(二)
  • 原文地址:https://www.cnblogs.com/gzshan/p/12634231.html
Copyright © 2020-2023  润新知