二叉树的层次遍历

文章详细介绍了二叉树和N叉树的层次遍历方法,包括简单层序、二叉树的层序遍历(自底向上、锯齿形)、N叉树层序遍历,以及在遍历过程中找到每层的最大值、平均值、右视图和最底层最左边节点的值。

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

1. 层次遍历

从根节点开始, 先访问根节点下面一层全部元素, 再访问之后的层次。

在这里插入图片描述

2. 基本的层序遍历与变换

遍历并输出全部元素,如下:

在这里插入图片描述

先访问根节点, 然后将其左孩子和右孩子放到队列里, 接着继续出队, 出来的元素都将其左右孩子放入队列里, 直到队列为空:

public static List<Integer> simpleLevelOrder(TreeNode root) {
  	if (root == null) {
        return new ArrayList<>();
    }
    List<Integer> res = new ArrayList<>();
    LinkedList<TreeNode> queue = new LinkedList<>();
    // 将根节点放入队列中
    queue.add(root);
    while (!queue.isEmpty()) {
        // 获取当前队列的长度, 这个长度相当于当前这一层的节点个数
        TreeNode node = queue.poll();
        res.add(node.val);
        if (node.left != null) {
            queue.add(node.left);
        }
        if (node.right != null) {
            queue.add(node.right);
        }
    }
    return res;
}

2.1 二叉树的层序遍历

给你一个二叉树,请你返回其按层序遍历得到的节点值。(即逐层地,从左到右访问所有节点)。

在这里插入图片描述

使用变量 size 来记录每一层的元素个数, 只要元素出队, 就将 size 减 1, 减到 0 就表示该层元素已经全部访问, 这时队列中的剩余的元素个数恰好就是下一层元素个数, 因此重新将 size 标记为下一层的元素个数就可以继续处理新的一行了, 例如在该题中:

  1. 首先拿到根节点 3, 其左右子节点都不为空, 将其左右子节点放入队列中。此时 3 出队, 剩余元素 9 和 20 恰好就是第二层的所有节点, size = 2。
  2. 第二层开始遍历, 9 出队, size 减1变为 1, 并将其子节点 8 和 13 入队。之后再将 20 出队, 并将其子节点 15 和 17 入队, 此时 size 减1 变为 0, 说明该层已经处理完了, 此时队列有 4 个元素, 而且就是下一层的元素个数。

代码实现:

public static List<List<Integer>> level102Order(TreeNode root) {
    if (root == null) {
        return new ArrayList<List<Integer>>();
    }

    List<List<Integer>> res = new ArrayList<List<Integer>>();
    LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
    //将根节点放入队列中,然后不断遍历队列
    queue.add(root);
    while (!queue.isEmpty()) {
        // 获取当前队列的长度, 也就是当前这一层的元素个数
        int size = queue.size();
        ArrayList<Integer> tmp = new ArrayList<>();
        // 将队列总的元素都拿出来, 放到临时的list集合中
        // 如果节点的左/右子树不为空, 也放入队列中
        for (int i = 0; i < size; i++) {
            TreeNode node = queue.poll();
            tmp.add(node.val);
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        // 此时的tmp就是当前层的全部元素
        res.add(tmp);
    }
    return res;
}

2.2 层序遍历-自底向上

给定一个二叉树,返回其节点值自底向上的层序遍历。(即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)。例如给定的二叉树为:

在这里插入图片描述
返回结果为:

[
[15,7],
[9,20],
[3]
]

思路: 在遍历完一层节点之后, 将存储该层节点值的列表添加到结果列表的尾部, 结果列表可以使用链表的结构

代码实现:

public static List<List<Integer>> levelOrderBottom(TreeNode root) {
    List<List<Integer>> levelOrder = new LinkedList<List<Integer>>();
    if (root == null) {
        return levelOrder;
    }
    Queue<TreeNode> queue = new LinkedList<TreeNode>();
    queue.add(root);
    while (!queue.isEmpty()) {
        List<Integer> tmp = new ArrayList<>();
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            TreeNode node = queue.poll();
            tmp.add(node.val);
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        levelOrder.add(0, tmp);
    }
    return levelOrder;
}

2.3 二叉树的锯齿形层序遍历

给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:

在这里插入图片描述

返回结果是:

[
[3],
[20,9],
[15,7]
]

思路: 为了满足题目要求的返回值为「先从左往右,再从右往左」交替输出的锯齿形,可以利用「双端队列」的数据结构来维护当前层节点值输出的顺序。双端队列是一个可以在队列任意一端插入元素的队列。对当前层节点的存储维护一个变量 isOrderLeft 记录是从左至右还是从右至左的:

  • 如果从左至右, 每次将被遍历到的元素插入至双端队列的末尾
  • 从右至左, 每次将遍历到的元素插入至双端队列的头部

在这里插入图片描述

代码实现:

public static List<List<Integer>> zigzagLevelOrder(TreeNode root) {
  	List<List<Integer>> ans = new LinkedList<List<Integer>>();
    if (root == null) {
        return ans;
    }
    Queue<TreeNode> queue = new LinkedList<TreeNode>();
    queue.add(root);
    boolean isOrderLeft = true;
    while (!queue.isEmpty()) {
        Deque<Integer> levelList = new LinkedList<>();
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            TreeNode node = queue.poll();
            if (isOrderLeft) {
                levelList.offerLast(node.val);
            } else {
                levelList.offerFirst(node.val);
            }
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        ans.add(new LinkedList<Integer>(levelList));
        isOrderLeft = !isOrderLeft;
    }
    return ans;
}

2.4 N 叉树的层序遍历

给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。

在这里插入图片描述

与二叉树的层序遍历基本一样, 借助队列即可实现:

在这里插入图片描述

public List<List<Integer>> nLevelOrder(Node root) {
    List<List<Integer>> value = new ArrayList<>();
    Deque<Node> q = new ArrayDeque<>();
    if (root != null)
        q.addLast(root);
    while (!q.isEmpty()) {
        Deque<Node> next = new ArrayDeque<>();
        List<Integer> nd = new ArrayList<>();
        while (!q.isEmpty()) {
            Node cur = q.pollFirst();
            nd.add(cur.val);
            for (Node chd : cur.children) {
                if (chd != null)
                    next.add(chd);
            }
        }
        q = next;
        value.add(nd);
    }
    return value;
}

3. 处理每层元素

3.1 在每个树行中找最大值

给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

在这里插入图片描述

思路: 在得到每一层之后使用变量来记录当前得到的最大值。

代码实现:

public List<Integer> largestValues(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    Deque<TreeNode> deque = new ArrayDeque<>();
    
    if (root != null) {
        deque.addLast(root);
    }
    
    while (!deque.isEmpty()) {
        int size = deque.size();
        int levelMaxNum = Integer.MIN_VALUE;
        for (int i = 0; i < size; i++) {
            TreeNode node = deque.poll();
            levelMaxNum = Math.max(node.val,levelMaxNum);
            if (node.left != null) deque.addLast(node.left);
            if (node.right != null) deque.addLast(node.right);
        }
        res.add(levelMaxNum);
    }
    return res;
}

3.2 在每个树行中找平均值

给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。

在这里插入图片描述

思路: 每层都将元素保存下来, 最后求平均。

代码实现:

public List<Double> averageOfLevels(TreeNode root) {
    List<Double> res = new ArrayList<>();
    if (root == null) return res;
    Queue<TreeNode> list = new LinkedList<>();
    list.add(root);
    while (list.size() != 0){
        int len = list.size();
        double sum = 0;
        for (int i = 0; i < len; i++){
            TreeNode node = list.poll();
            sum += node.val;
            if (node.left != null) list.add(node.left);
            if (node.right != null) list.add(node.right);
        }
        res.add(sum/len);
    }
    return res;
}

3.3 二叉树的右视图

给定一个二叉树的根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。例如:

在这里插入图片描述

思路: 记录下每层最后一个元素。

代码实现:

public List<Integer> rightSideView(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            TreeNode node = queue.poll();
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
            if (i == size - 1) {  //将当前层的最后一个节点放入结果列表
                res.add(node.val);
            }
        }
    }
    return res;
}

3.4 最底层最左边

给定一个二叉树的 根节点root,请找出该二叉树的 最底层 最左边 节点的值。

在这里插入图片描述
假设二叉树中至少有一个节点。

示例1:
输入: root = [2,1,3]
输出: 1

示例2:
输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7

思路: 正常执行层次遍历时, 不管最底层有几个元素, 最后一个输出的一定是最底层最右的元素。所以如果我们将每一层的元素先反转再放入队列, 那么最后一个输出的就是最左元素。

代码实现:

public int findBottomLeftValue(TreeNode root) {
    if (root.left == null && root.right == null) {
        return root.val;
    }
    
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    TreeNode temp = new TreeNode(-100);
    
    while (!queue.isEmpty()) {
        temp = queue.poll();
        if (temp.right != null) {
            // 先把右节点加入 queue
            queue.offer(temp.right);
        }
        if (temp.left != null) {
            // 再把左节点加入 queue
            queue.offer(temp.left);
        }
    }
    return temp.val;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值