二叉树层序遍历实现以及练习扩展

本文详细介绍了二叉树的层序遍历方法,包括使用队列的实现,递归模拟类似层序遍历的效果,以及如何扩展练习,如层序遍历的逆序、右视图、平均值计算和树的深度查找。
摘要由CSDN通过智能技术生成

一.二叉树层序遍历

1.介绍

层序遍历类似于广度优先搜索,它按照二叉树的层次从上到下、从左到右遍历二叉树的每个节点。
每次遍历一层元素,借助队列实现,
首先叶子节点入队,然后左节点不为空时入队,右节点不为空时入队,
每次扩张当前层元素,size统计当前元素个数,然后挨个扩张,将该结点的左右孩子加入队列

 

2.代码实现

层序遍历就是一层一层处理元素,每次遍历每层size个,对于每层的每个元素,加入集合,然后扩展左右孩子入队作为下一层元素,本遍历完后更新size开始下一层

首先根结点入队,第一层个数就是1,记下size,对第一层处理,只处理前size个,加入数组,拓展左右孩子入队,然后更新size,处理第二层,加入数组,拓展左右孩子入队

1.队列方式

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> resList = new ArrayList<>();//结果集合
        if (root == null) return resList;
        Queue<TreeNode> queue = new LinkedList<>();//创建对列
        queue.offer(root);//根结点入队

        while (!queue.isEmpty()) {//队不为空时
            int len = queue.size(); //遍历本层元素size个 
            // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
            List<Integer> tempList = new ArrayList<>();
            while (len > 0) {//遍历本层元素size个
                TreeNode tempNode = queue.poll();
                tempList.add(tempNode.val);//数值加入当前层结果中
                if (tempNode.left != null) queue.offer(tempNode.left);//左孩子入队
                if (tempNode.right != null) queue.offer(tempNode.right);//右孩子入队
                len--;
            }
            resList.add(tempList);//当前层结果加入最终结果
        }

        return resList;
    }
}

2.递归方式 dfs

在Java中,递归方式实现二叉树的层序遍历并不常见,因为层序遍历(广度优先遍历)通常使用队列来实现。然而,如果使用递归来实现类似层序遍历的效果(虽然这并不是真正的层序遍历,而是深度优先遍历),可能需要实现一个类似的前序遍历,并在遍历的过程中记录每个节点的层级。

通过传递层级信息deep和使用一个列表的列表resList来存储每一层的节点值,模拟了类似层序遍历的输出结构。

import java.util.ArrayList;  
import java.util.List;  
  
class TreeNode {  
    int val;  
    TreeNode left;  
    TreeNode right;  
  
    TreeNode(int x) {  
        val = x;  
    }  
}  
  
public class BinaryTreeTraversal {  
  
    // 用于存储结果的列表的列表  
    private List<List<Integer>> resList = new ArrayList<>();  
  
    // 递归函数,模拟类似层序遍历的效果  
    public void checkFun01(TreeNode node, Integer deep) {  
        if (node == null) return; // 如果节点为空,则直接返回  
  
        deep++; // 层级加1  
  
        // 当结果列表的size小于当前层级时,添加一个新的列表来存储该层级的节点值  
        if (resList.size() < deep) {  
            List<Integer> item = new ArrayList<>();  
            resList.add(item);  
        }  
  
        // 将当前节点的值添加到对应层级的列表中  
        resList.get(deep - 1).add(node.val);  
  
        // 递归遍历左子树,层级信息不变(因为是同一层级的不同分支)  
        checkFun01(node.left, deep);  
  
        // 递归遍历右子树,层级信息不变(因为是同一层级的不同分支)  
        checkFun01(node.right, deep);  
    }  
  
    // 测试方法  
    public static void main(String[] args) {  
        BinaryTreeTraversal traversal = new BinaryTreeTraversal();  
  
        // 创建一个二叉树  
        //       1  
        //      / \  
        //     2   3  
        //    / \   \  
        //   4   5   6  
        TreeNode root = new TreeNode(1);  
        root.left = new TreeNode(2);  
        root.right = new TreeNode(3);  
        root.left.left = new TreeNode(4);  
        root.left.right = new TreeNode(5);  
        root.right.right = new TreeNode(6);  
  
        // 调用递归方法  
        traversal.checkFun01(root, 1); // 从层级1开始  
  
        // 打印结果  
        for (List<Integer> level : traversal.resList) {  
            System.out.println(level);  
        }  
    }  
}

 二.练习扩展

 1.二叉树的层序遍历2

 

思路

相对于102.二叉树的层序遍历,就是最后把result数组反转一下就可以了。

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
class Solution {
  public List<List<Integer>> levelOrderBottom(TreeNode root) {

        List<List<Integer>> res=new ArrayList<>();
        List<List<Integer>> res1=new ArrayList<>();
        Queue<TreeNode> queue=new LinkedList<>();
        //层序遍历二叉树
        if(root==null){
            return res;
        }
        queue.offer(root);
        while (!queue.isEmpty()){
            List<Integer> list=new ArrayList<>();
            int size=queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode poll = queue.poll();
                list.add(poll.val);
                if(poll.left!=null){
                    queue.offer(poll.left);
                }
                if(poll.right!=null){
                    queue.offer(poll.right);
                }
            }
            res.add(list);
        }
        for (int i = res.size()-1; i>=0;i--) {
            res1.add(res.get(i));
        }
        return res1;

    }
}

2.二叉树的右视图

 

 

思路

层序遍历的时候,遍历到单层的最后面的元素放进result数组中,随后返回result就可以了。

class Solution {  
    // 声明一个队列用于层序遍历  
    Queue<TreeNode> queue = new LinkedList<>();  
  
    public List<Integer> rightSideView(TreeNode root) {  
        // 创建一个列表用于存储每一层最右侧的节点值  
        List<Integer> res = new ArrayList<>();  
  
        // 如果根节点为空,则直接返回空列表  
        if (root == null) {  
            return res;  
        }  
  
        // 将根节点加入队列  
        queue.offer(root);  
  
        // 当队列不为空时,进行层序遍历  
        while (!queue.isEmpty()) {  
            // 创建一个临时列表用于存储当前层的节点值  
            List<Integer> list = new ArrayList<>();  
  
            // 获取当前层的节点数量  
            int size = queue.size();  
  
            // 遍历当前层的所有节点  
            while (size > 0) {  
                // 出队一个节点,并将其值加入临时列表  
                TreeNode poll = queue.poll();  
                list.add(poll.val);  
  
                // 如果左子节点不为空,则将其加入队列  
                if (poll.left != null) {  
                    queue.offer(poll.left);  
                }  
  
                // 如果右子节点不为空,则将其加入队列  
                if (poll.right != null) {  
                    queue.offer(poll.right);  
                }  
  
                // 当前层遍历的节点数减一  
                size--;  
            }  
  
            // 将当前层最右侧的节点值(即临时列表的最后一个元素)加入结果列表  
            res.add(list.get(list.size() - 1));  
        }  
  
        // 返回结果列表  
        return res;  
    }  
}  
  
// 假设TreeNode类已经定义如下:  
// class TreeNode {  
//     int val;  
//     TreeNode left;  
//     TreeNode right;  
//     TreeNode(int x) { val = x; }  
// }

3.二叉树的层平均值

 

 

思路

层序遍历的时候把一层求个总和在取一个均值。

class Solution {  
   
 public List<Double> averageOfLevels(TreeNode root) {  
        // 创建一个列表用于存储每一层的平均值  
        List<Double> avg = new ArrayList<>();  
  
        // 创建一个队列用于层序遍历  
        Queue<TreeNode> queue = new LinkedList<>();  
  
        // 将根节点加入队列  
        if (root != null) {  
            queue.offer(root);  
        }  
  
        // 当队列不为空时,说明还有节点需要遍历  
        while (!queue.isEmpty()) {  
            // 初始化当前层的和  
            double sum = 0;  
  
            // 获取当前层的节点数量  
            int size = queue.size();  
  
            // 遍历当前层的所有节点  
            for (int i = 0; i < size; i++) {  
                // 出队一个节点  
                TreeNode node = queue.poll();  
  
                // 累加当前节点的值  
                sum += node.val;  
  
                // 如果左子节点不为空,将其加入队列  
                if (node.left != null) {  
                    queue.offer(node.left);  
                }  
  
                // 如果右子节点不为空,将其加入队列  
                if (node.right != null) {  
                    queue.offer(node.right);  
                }  
            }  
  
            // 计算当前层的平均值,并添加到结果列表中  
            avg.add(sum / size);  
        }  
  
        // 返回每一层的平均值列表  
        return avg;  
    }  
}

4.二叉树的最大深度

 深度  某个节点到根节点距离从1开始计算
高度 某节点到叶子节点距离 从1开始计算

思路

使用层序遍历是最合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。

在二叉树中,一层一层的来遍历二叉树,记录一下遍历的层数就是二叉树的深度

class Solution {  
   // 计算二叉树的最大深度  
    public int maxDepth(TreeNode root) {  
        // 如果根节点为空,则树的深度为0  
        if (root == null) {  
            return 0;  
        }  
   // 使用队列进行层序遍历  
        Queue<TreeNode> que = new LinkedList<>();  
        // 将根节点加入队列  
        que.offer(root);  
  
        // 初始化深度为1(因为已经有一个根节点了)  
        int depth = 1;  
  
        // 当队列不为空时,说明还有节点需要遍历  
        while (!que.isEmpty()) {  
            // 当前层的节点数量  
            int len = que.size();  
  
            // 遍历当前层的所有节点  
            while (len > 0) {  
                // 出队一个节点  
                TreeNode node = que.poll();  
  
                // 如果节点的左子节点不为空,则将左子节点加入队列  
                if (node.left != null) {  
                    que.offer(node.left);  
                }  
  
                // 如果节点的右子节点不为空,则将右子节点加入队列  
                if (node.right != null) {  
                    que.offer(node.right);  
                }  
  
                // 遍历完一个节点后,当前层的节点数量减一  
                len--;  
            }  
  
            // 完成当前层的遍历后,深度加1,因为已经遍历到了下一层  
            depth++;  
        }  
  
        // 返回二叉树的最大深度  
        return depth;  
    }  
}

 5.二叉树的最小深度

 

思路

相对于二叉树的最大深度 ,本题也可以使用层序遍历的方式来解决,思路是一样的。

需要注意,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点

class Solution {
    public int minDepth(TreeNode root){
        if (root == null) {
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int depth = 0;
        while (!queue.isEmpty()){
            int size = queue.size();
            depth++;
            TreeNode cur = null;
            for (int i = 0; i < size; i++) {
                cur = queue.poll();
                //如果当前节点的左右孩子都为空,直接返回最小深度
                if (cur.left == null && cur.right == null){
                    return depth;
                }
                if (cur.left != null) queue.offer(cur.left);
                if (cur.right != null) queue.offer(cur.right);
            }
        }
        return depth;
    }
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河清风悠

你的鼓励就是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值