二叉树的层序遍历 bfs(通过队列实现bfs)

本文详细介绍了二叉树的层次遍历方法,包括BFS(广度优先搜索)策略,重点讲解了核心代码实现,如层序遍历、倒序遍历、右视图、最大值查找等。同时,讨论了图的层次遍历,如01矩阵问题,强调了邻接矩阵和邻接表在存储图结构中的作用。通过实例展示了如何运用层次遍历解决实际问题。

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

 队列元素从队尾进,从队头出

 

树形bfs:

核心:

step1:将队头节点移出队列

step2:然后将这个结点的左右孩子结点加入队列

        Queue queue = new LinkedList();

        //先将根节点加入队列
        queue.add(root);

        //只要队列里还存在元素
        while(queue.size()!=0)
        {
            //求出队列中此时有几个元素,这些元素都要出队列,而且出队列后要把它们的左右孩子都加入队列
            int  size=queue.size();

            for(int i=0;i<size;i++)
            {
                Node current=queue.remove();//将队头结点移出队列
                
                //将刚刚移出队列的结点的左右孩子结点加入队列
                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                if(current.right!=null)
                {
                    queue.add(current.right);
                }
            }
        }

每一轮size是多少,就说明这一层有多少个结点




102

非递归解法:

(1) 这里有个核心:每一轮开始的时候(把上一轮的节点全部出队列之后)都会计算此时队列的长度,此时队列的长度就是二叉树某一层的节点个数,将这一层的节点值全部添加到临时arraylist中,然后开始下一轮(也就是下一层)

也就是说这就是在遍历每一层

(2)每次出队列1个结点,就把这个结点的左右孩子都入队列,每一轮将一层结点出队列

class Node
{
    int val;
    Node left;
    Node right;
    public Node(int val)
    {
        this.val=val;
    }
}
class Solution
{
    //传入根节点
    public static ArrayList levelOrderTraverse(Node root)
    {
        //最后的结果数组是“数组的数组”形式
        //比如:[[1],[2,3],[4,5,6,7]]
        ArrayList result=new ArrayList();
        if(root==null)
        {
            return result;
        }
        //创建队列,队列里装的是结点
        Queue queue=new LinkedList();

        //将根节点入队列,此时root就是队头结点
        queue.offer(root);
        //只要队列不为空,就一直循环(开始时队列中有头结点这一个数,队列不为空,进入循环)
        while(queue.isEmpty()==false)
        {
           //统计出此时队列的长度,此时队列的长度是多少,就说明这一层有几个结点,这句话非常非常非常关键
            int size=queue.size();

            //每一层的节点的值用一个数组来装,装完一层就把这个数组添加到结果数组中
            //注意里面装的是结点的值,不是结点
            ArrayList temp=new ArrayList();

            //每一轮把一层的结点全部弹出队列,并且把这一层结点的左右孩子结点全部加进队列
            for(int i=0;i<size;i++)
            {
               //queue.poll()方法表示返回队头元素,并且在队列中删除
                // 所以这里会把队头结点删除并且赋给current
               Node current=(Node)queue.poll();
               //将刚刚删除的队头结点的值添加到temp数组中
               temp.add(current.val);


               if(current.left!=null)
               {
                   queue.add(current.left);
               }
               if(current.right!=null)
               {
                   queue.add(current.right);
               }
            }
            result.add(temp);
        }
        return result;
    }
}

public class test
{
    public static void main(String[] args) {
        Node root = new Node(1);

        root.left = new Node(2);
        root.right = new Node(3);

        root.left.left = new Node(4);
        root.right.right = new Node(8);

        Solution solution = new Solution();

        ArrayList a = solution.levelOrderTraverse(root);
        System.out.println(a);
        //[[1], [2, 3], [4, 8]]
    }
}

 核心代码就是这一段:核心就是需要将每一个移出队列的结点的左右孩子结点加入队列

        Queue queue = new LinkedList();

        //先将根节点加入队列
        queue.add(root);

        //只要队列里还存在元素
        while(queue.isEmpty()==false)
        {
            //求出队列中此时有几个元素,这些元素都要出队列,而且出队列后要把它们的左右孩子都加入队列
            int  size=queue.size();

            for(int i=0;i<size;i++)
            {
                Node current=queue.remove();//将队头结点移出队列
                
                //将刚刚移出队列的结点的左右孩子结点加入队列
                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                if(current.right!=null)
                {
                    queue.add(current.right);
                }
            }
        }

如果是429. N 叉树的层序遍历 - 力扣(LeetCode)

只需将核心代码改成:

                
               Node current=(Node)queue.poll();
               //将刚刚删除的队头结点的值添加到temp数组中
               temp.add(current.val);
               for(Node child:node.children)
               {
                   if(child!=null)
                   {
                      queue.add(child);
                   }
              }

也就是说将队列中一个节点出队列后,不是将这个节点的左右孩子节点入队,而是需要将这个节点的所有孩子节点都入队

class Solution 
{
    public List<List<Integer>> levelOrder(Node root) 
    {
        ArrayList result=new ArrayList();
        if(root==null)
        {
            return result;
        }

        Queue<Node> queue=new LinkedList();
        
        queue.offer(root);
        
        //队列不为空,就要继续
        while(queue.isEmpty()==false)
        {
            int size=queue.size();
             
            ArrayList temp=new ArrayList();

            for(int i=0;i<size;i++)
            {
                Node current=queue.poll();
                temp.add(current.val);

                for(Node child:current.children)
                {
                   if(child!=null)
                   {
                      queue.add(child);
                   }
                }
            }
            result.add(temp);
        }  
        return result;    
    }
}

107. 二叉树的层序遍历 II - 力扣(LeetCode)

只需将二叉树层序遍历的得到的数组进行反转即可

即多加上这句代码就可以了:

Collections.reverse(result);
class Solution 
{
    public List<List<Integer>> levelOrderBottom(TreeNode root) 
    {
        List<List<Integer>> result=new ArrayList();
        if(root==null)
        {
            return result;
        }
 
        Queue<TreeNode> queue=new LinkedList();
        
        queue.offer(root);
        
        //队列不为空,就要继续
        while(queue.isEmpty()==false)
        {
            int size=queue.size();
             
            List<Integer> temp=new ArrayList();
 
            for(int i=0;i<size;i++)
            {
                TreeNode current=queue.poll();
                temp.add(current.val);
  
                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                  if(current.right!=null)
                {
                    queue.add(current.right);
                }         
            }
            result.add(temp);
        }  
        Collections.reverse(result);  
        return result;
    }
}

199. 二叉树的右视图 - 力扣(LeetCode)

其实就是把每一层的最后一个元素加入到列表中返回


class Solution 
{
    public List<Integer> rightSideView(TreeNode root)
    {
        List<Integer> result=new ArrayList();
        if(root==null)
        {
            return result;
        }
 
        Queue<TreeNode> queue=new LinkedList();
        
        queue.offer(root);
        
        //队列不为空,就要继续
        while(queue.isEmpty()==false)
        {
            int size=queue.size();
 
            for(int i=0;i<size;i++)
            {
                TreeNode current=queue.poll();

                if(i==size-1)
                {
                    result.add(current.val);
                }

                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                  if(current.right!=null)
                {
                    queue.add(current.right);
                }         
            }        
        }  
        return result;
    }
}

515. 在每个树行中找最大值 - 力扣(LeetCode)

class Solution 
{
    public List<Integer> largestValues(TreeNode root) 
    {
        
        List<Integer> result=new ArrayList();
        if(root==null)
        {
            return result;
        }
 
        Queue<TreeNode> queue=new LinkedList();
        
        queue.offer(root);
        
        //每一轮负责找出一层的二叉树的节点
        while(queue.isEmpty()==false)
        {
            int size=queue.size();
 
            int temp=Integer.MIN_VALUE;
            for(int i=0;i<size;i++)
            {
                TreeNode current=queue.poll();
                if(current.val>temp)
                {
                    temp=current.val;
                }
                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                  if(current.right!=null)
                {
                    queue.add(current.right);
                }         
            } 
            result.add(temp);       
        }  
        return result;

    }
}

637. 二叉树的层平均值 - 力扣(LeetCode)

class Solution 
{
    public List<Double> averageOfLevels(TreeNode root) 
    {
        List result=new ArrayList();
        if(root==null)
        {
            return result;
        }
 
        Queue<TreeNode> queue=new LinkedList();
        
        queue.offer(root);
        
        //每一轮负责找出一层的二叉树的节点
        while(queue.isEmpty()==false)
        {
            int size=queue.size();
 
            double temp=0;
            for(int i=0;i<size;i++)
            {
                TreeNode current=queue.poll();
                temp=temp+current.val;
                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                  if(current.right!=null)
                {
                    queue.add(current.right);
                }         
            } 
            temp=temp/size;
            result.add(temp);       
        }  
        return result;

    }
}

117. 填充每个节点的下一个右侧节点指针 II - 力扣(LeetCode)

class Solution 
{
    public Node connect(Node root) 
    {

         List result=new ArrayList();
        if(root==null)
        {
            return root;
        }
 
        Queue<Node> queue=new LinkedList();
        
        queue.offer(root);
        
        //每一轮负责找出一层的二叉树的节点
        while(queue.isEmpty()==false)
        {
            int size=queue.size();
 
            Node dummy=new Node(-1);
            for(int i=0;i<size;i++)
            {
                Node current=queue.poll();
                dummy.next=current;
                dummy=current;
                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                  if(current.right!=null)
                {
                    queue.add(current.right);
                }         
            }    
        }  
        return root;      
    }
}

力扣103 二叉树的锯齿形层次遍历

就是增加一个标志位flag,flag=1,奇数行,那就不反转列表

                                          flag=0,偶数行,反转列表

class Solution 
{
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) 
    {
        List<List<Integer>> result=new ArrayList();
        if(root==null)
        {
            return result;
        }
 
        Queue<TreeNode> queue=new LinkedList();
        
        queue.offer(root);
        
        int flag=1;
        //队列不为空,就要继续
        while(queue.isEmpty()==false)
        {
            int size=queue.size();
             
            List<Integer> temp=new ArrayList();
 
            for(int i=0;i<size;i++)
            {
                TreeNode current=queue.poll();
                temp.add(current.val);
  
                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                  if(current.right!=null)
                {
                    queue.add(current.right);
                }         
            }
            if(flag<0)  Collections.reverse(temp);
            flag=-flag;
            result.add(temp);
        }  
        return result;

    }
}

 力扣1161 求出和最大的那一层层号

class Solution 
{
    public int maxLevelSum(TreeNode root)
    {
        int  num=1;//统计当前到了第几层

        int result=1;
        int sum=Integer.MIN_VALUE;//预防每个节点值都是负数情况
 
        Queue<TreeNode> queue=new LinkedList();
        
        queue.offer(root);
        
        //每一轮负责找出一层的二叉树的节点
        while(queue.isEmpty()==false)
        {
            int size=queue.size();
 
            int temp=0;
            for(int i=0;i<size;i++)
            {
                TreeNode current=queue.poll();
                temp=temp+current.val;
                if(current.left!=null)
                {
                    queue.add(current.left);
                }
                  if(current.right!=null)
                {
                    queue.add(current.right);
                }         
            } 
            if(temp>sum)
            {
                sum=temp;
                result=num;
            }
            num++;//nums用来记录层数,表示到了第几层
            
        }  
        return result;

    }
}

力扣513 找树左下角的值(二叉树最底层最左边的值)

class Solution
{
    public int findBottomLeftValue(TreeNode root) 
    {
      
        ArrayList<ArrayList<Integer>> result=new ArrayList();
 
  
        Queue queue=new LinkedList();

        
        queue.offer(root);
       
        while(queue.isEmpty()==false)
        {
        
            int size=queue.size();

            ArrayList temp=new ArrayList();

          
            for(int i=0;i<size;i++)
            {
             
               TreeNode current=(TreeNode)queue.poll();
               

               temp.add(current.val);


               if(current.left!=null)
               {
                   queue.add(current.left);
               }
               if(current.right!=null)
               {
                   queue.add(current.right);
               }
            }
            result.add(temp);
        }
        return result.get(result.size()-1).get(0);
    }
}

力扣1302 层数最深叶子节点的和

class Solution 
{
    public int deepestLeavesSum(TreeNode root)
    {
        ArrayList<ArrayList<Integer>> result=new ArrayList();
 
  
        Queue queue=new LinkedList();

        
        queue.offer(root);
       
        while(queue.isEmpty()==false)
        {
        
            int size=queue.size();

            ArrayList temp=new ArrayList();

          
            for(int i=0;i<size;i++)
            {
             
               TreeNode current=(TreeNode)queue.poll();
               

               temp.add(current.val);


               if(current.left!=null)
               {
                   queue.add(current.left);
               }
               if(current.right!=null)
               {
                   queue.add(current.right);
               }
            }
            result.add(temp);
        }
        int num=0;
        for(int i=0;i<result.get(result.size()-1).size();i++)
        {
            num=num+ result.get(result.size()-1).get(i);
        }
        return num;
    }
}

图bfs:

存储图的两种方式:邻接矩阵和邻接表

 力扣 542  01矩阵

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值