树的层次遍历

层次遍历简介

        广度优先在面试里出现的频率非常高,整体属于简单题。而广度优先遍历又叫做层次遍历,基本过程如下:

image.png

        层次遍历就是从根节点开始,先访问根节点下面一层全部元素,再访问之后的层次,类似金字塔一样,逐层访问。我们可以看到上面例子就是从左到右一层一层遍历二叉树,先访问3,之后访问1的左右孩子9和10,之后分别访问9和20的左右孩子[4,5]和[6,7] ,最后得到结果[3,9,20,8,13,15,7]

        这里需要关注的问题是:将遍历过的元素的左右孩子保存起来。例如:访问9时,其左右孩子8和13应该先保存一下,直到处理20之后才会处理。使用队列就是一个比较好的方法。

        以上图为例,过程如下

  1. 先将3入队(使用链表实现的队列)
  2. 然后3出队,接着将3的左右孩子9和10  保存在队列中
  3. 然后9 出队,将9的左右孩子8和13入队
  4. 接着20出队,将15和7入队
  5. 最后8  13  15  7  分别出队,此时都是叶子节点了,没有入队的元素了。 

拓展

如果能将树的每层次分开了,是否可以整点新花样?

        首先,能否将每层的元素顺序给反转一下呢?

        能否奇数行不变,只将偶数行反转呢?

        能否将输出层次从低到root逐层输出呢?

        再来,既然能拿到每一层的元素了,能否找到当前层最大的元素? 最小的元素? 最右的元素(右视图)? 最左的元素(左视图) ? 整个层的平均值? 

而以上问题就是经典的层次遍历题。

题号如下

102.二又树的层序遍历
107.二又树的层次遍历lIl
199.二又树的右视图
637.二又树的层平均值
429.N又树的前序遍历
515.在每个树行中找最大值
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针Il
103 锯齿层序遍历 

基本的层序遍历与变换

题目

        遍历并输出全部元素,二叉树示例如下:

*              3
*            /   \
*          9      20
*                 /  \
*               15   7

代码实现思路

         先访问根节点,然后将其左右孩子放到队列里,接着继续出队列;出来的元素,将其左右孩子放入队列中,直到队列为空了才退出来。

代码实现

节点代码

public TreeNode{public int data;public TreeNode left;public TreeNode right;public TreeNode(int data){this.data = data;}
}

实现代码

public List<Integer> simpleLevelTraverse(TreeNode root){// 创建一个数组实现的集合接收遍历后的结果List<Integer> res = new ArrayList<>();// 如果该树是一颗空树,返回空的集合if(root == null){return res;}// 使用链表当做队列,用于存储树的节点// 从尾插入,从头删除LinkedList<TreeNode> queue = new LinkedList<>();// 将根节点放入队列中,然后不断遍历根节点queue.add(root);// 有多少元素就遍历多少次while(queue.size() > 0){// remove():获取并移除此队列的头(第一个元素)TreeNode t = queue.remove();// 使用集合搜集遍历后的节点数据部分res.add(t.data);// 如果该节点有左节点(不为空),则将其加入队列中,用于下次遍历if(t.left != null){queue.add(t.left);}// 如果该节点有右节点(不为空),则将其加入队列中,用于下次遍历if(t.right != null){queue.add(t.right);}}// 返回遍历后的结果return res;}

         根据树的结构可以看到,一个节点在一层访问之后,其子孩子都是在下一层按照FIFO的顺序处理的,因此,队列就相当于一个缓冲区。这题是逐层自左向右执行的,如果将每层的元素分开打印,便有了另一种题目。

二叉树的层序遍历(每层元素分开打印)

题目

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

示例

     * 二叉树:[3,9,20,null,null,15,7]*              3*            /   \*          9      20*                 /  \*               15   7
*        返回后程序遍历结果*        [*        [3],*        [9,20],*        [15,7]*        ]

 解析

        此题依旧可以使用队列存储每一层的节点。但题目要求逐层节点打印,那就需要考虑某一层是否访问完。针对这个问题,可以使用一个变量size标记一下某一层的元素个数,只要出队列一个节点,就将size的值减1,减到0,说明该层元素访问完了(当然,也可以从0开始遍历,遍历到size个的时候(i < size)就说明这一层的节点都访问过了),然后重新将size标记为下一层节点的个数,继续执行(因此,size需要在循环中创建)。

        对于结果集,可以看作外层一个集合(用于存储层数),里面一层集合(用于存储每一层的节点值)

代码实现 

public List<List<Integer>> getEveryLevelNodeFromTop(TreeNode root){List<List<Integer>> res = new ArrayList<List<Integer>>>();if(root == null){return res;}LinkedList<TreeNode> queue = new LinkedList<>();queue.add(root);while(queue.size()>0){List<Integer> temp = new  ArrayList<>();int size = queue.size();   for(int i = 0 ; i < size ; i++){TreeNode t = queue.remove();temp.add(t.data);if(t.left != null){queue.add(t.left);}if(t.right != null){queue.add(t.right);}}res.add(temp);}return res;
}

重要性

         上面的代码是整个算法体系的核心算法之一,与链表反转、二分查找属于同一个级别!

层序遍历(自底向上)

题目

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

*              3
*            /   \
*          9      20
*                 /  \
*               15   7

示例

[

        [15,7],

        [9,20],

        [3]

]

分析

        如果要求从上到下输出每一层的节点值,做法是很直观的。在遍历完一层节点之后,将存储该层节点值的列表添加到结果列表的尾部。这道题要求从下到上输出每一层的节点值,只要对上述操作稍作修改即可在遍历完一层节点之后,将存储该层节点值的列表添加到结果列表的头部。 

        为了降低在结果列表的头部添加一层节点值的列表的时间复杂度,结果列表可以使用链表的结构,在链表头部添加一层节点值的列表的时间复杂度是 O(1)。在 Java 中,由于我们需要返回的 List 是一个接口,这里可以使用链表实现。

代码实现 

public List<List<Integer>> getEveryNodeFromBottom(TreeNode root){List<List<Integer>> res = new LinkedList<List<Integer>>();if(root == null){return res;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while(! queue.isEmpty()){List<Integer> temp = new ArrayList<>();int size = queue.size();for(int i = 0 ; i < size ; i++){TreeNode t = queue.pull();temp.add(t.data);TreeNode left = t.left , right = t.right;if(left != null){queue.offer(left);}if(right != null){queue.offer(right);}}// 栈结构:将先进入结果集的集合放入后面res.add(0,temp);}return res;
}

二叉树的锯齿形遍历

题目

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

*              3
*            /   \
*          9      20
*                 /  \
*               15   7

示例

[

        [3],

        [20,9],

        [15,7]

]

分析

        这个题与之前的区别只是最后输出的要求有所变化,要求我们按层数的奇偶来决定每一层的输出顺序如果当前层数是偶数,从左至右输出当前层的节点值,否则,从右至左输出当前层的节点值。为了满足题目要求的返回值为[先从左往右,再从右往左]交替输出的锯齿形,可以利用[双端队列,的数据结构来维护当前层节点值输出的顺序。双端队列是一个可以在队列任意一端插入元素的队列。在广度优先搜索遍历当前层节点拓展下一层节点的时候我们仍然从左往右按顺序拓展,但是对当前层节点的存储我们维护一个变量 isOrderLeft 记录是从左至右还是从右至左的:
        如果从左至右,我们每次将被遍历到的元素插入至双端队列的末尾。
        从右至左,我们每次将被遍历到的元素插入至双端队列的头部。

代码实现

  /*** 给定一个二叉树,返回其节点值的锯齿形层序遍历(即:先从左往右,再从右往左进行下一层遍历。以此类推,层与层之间交替执行)* @param root 树的根节点* @return 交替执行的遍历结果*/public List<List<Integer>> levelOrderBetweenLeftAndRight(TreeNode root){LinkedList<List<Integer>> res = new LinkedList<List<Integer>>();if (root == null){return res;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);boolean isOrderLeft = true;while (!queue.isEmpty()){Deque<Integer> levelLeft = new LinkedList<Integer>();int size = queue.size();for (int i = 0; i < size; i++) {TreeNode curNode = queue.remove();if (isOrderLeft){levelLeft.offerLast(curNode.data);}else {levelLeft.offerFirst(curNode.data);}if (curNode.left != null){queue.add(curNode.left);}if (curNode.right != null) {queue.add(curNode.right);}}res.add(new LinkedList<>(levelLeft));isOrderLeft = !isOrderLeft;}return res;}

层次遍历(N叉树) 

 题目

        给定一个 N 又树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)树的序列化输入是用层序遍历,每组子节点都由 null 值分隔 (参见示例)。

 示例

输入: root = [1,null,3,2,4,nu11,5,6](表述树的元素是这个序列)

输出: [[1],[3,2,4],[5,6]]

代码实现

N叉树代码

class MutilTreeNode {public int data ;public List<MutilTreeNode> children;
}

实现 

public List<List<Integer>> nLevelOrder(MutilTreeNode root){ArrayList<List<Integer>> res = new ArrayList<>();Deque<MutilTreeNode> deque = new LinkedList<>();if (root != null){//Java中的java.util.LinkedList.addLast()方法用于在LinkedList的末尾插入特定元素。deque.addLast(root);}while (! deque.isEmpty()){ArrayList<Integer> nd = new ArrayList<>();ArrayDeque<MutilTreeNode> next = new ArrayDeque<>();while (! deque.isEmpty()){MutilTreeNode cur = deque.pollFirst();nd.add(cur.data);for (MutilTreeNode child : cur.children) {if (child != null){next.add(child);}}deque = next;res.add(nd);}}return res;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24264.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Uniapp 的APP热更新】

Uniapp 的APP热更新功能依赖于其打包工具 HBuilder&#xff0c;具体步骤如下&#xff1a; 1. 在 HBuilder 中构建并打包出应用程序 具体步骤&#xff1a; 1.点击发行&#xff0c;点击制作wgt包 2.根据需求修改文件储存路径和其他配置&#xff0c;点击确定 3.等待打包完成&a…

Rust中的高吞吐量流处理

本篇文章主要介绍了Rust中流处理的概念、方法和优化。作者不仅介绍了流处理的基本概念以及Rust中常用的流处理库&#xff0c;还使用这些库实现了一个流处理程序。 最后&#xff0c;作者介绍了如何通过测量空闲和阻塞时间来优化流处理程序的性能&#xff0c;并将这些内容同步至…

Android 实现账号诊断动画效果,逐条检测对应的项目

Dialog中的项目 逐条检测效果&#xff1a; 依赖库&#xff1a; implementation com.github.li-xiaojun:XPopup:2.9.19 implementation com.blankj:utilcodex:1.31.1 implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.101、item_account_check.xml <…

PictureBox基本使用

作用&#xff1a;展示图片&#xff0c;同时也具有click属性&#xff0c;可用充当按钮功能。 常用属性&#xff1a; 设置图片 设置图片的填充模式 常用事件&#xff1a; 后台代码示范&#xff1a;增加点击事件 private void pictureBox1_Click(object sender, EventArgs e){//…

【CodeWhisperer】亚马逊版代码生成工具

大家好&#xff0c;我是荷逸&#xff0c;今天给大家带来的是代码生成工具【CodeWhisperer】 CodeWhisperer简介 CodeWhisperer是亚⻢逊出品的一款基于机器学习的通用代码生成器&#xff0c;可实时提供代码建议。 在编写代码时&#xff0c;它会自动根据我们现有的代码和注释生…

Java中「Future」接口详解

一、背景 在系统中&#xff0c;异步执行任务&#xff0c;是很常见的功能逻辑&#xff0c;但是在不同的场景中&#xff0c;又存在很多细节差异&#xff1b; 有的任务只强调「执行过程」&#xff0c;并不需要追溯任务自身的「执行结果」&#xff0c;这里并不是指对系统和业务产…

JDK, JRE和JVM之间的区别和联系

JDK, JRE和JVM是与Java编程语言相关的三个重要的概念&#xff0c;它们分别代表Java Development Kit&#xff08;Java开发工具包&#xff09;、Java Runtime Environment&#xff08;Java运行时环境&#xff09;和Java虚拟机&#xff08;Java Virtual Machine&#xff09;。它们…

大数据课程G2——Hbase的基本架构

文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 掌握Hbase的基本架构; ⚪ 掌握Hbase的读写流程; ⚪ 掌握Hbase的设计与优化; 一、基本架构 1. HRegion 1. 在HBase中,会将一个表从行键方向上进行切分,切分成1个或者多个HRegion。 …

C#利用自定义特性以及反射,来提大型项目的开发的效率

在大型项目的开发过程中&#xff0c;需要多人协同工作&#xff0c;来加速项目完成进度。 比如一个软件有100个form&#xff0c;分给100个人来写&#xff0c;每个人完成自己的Form.cs的编写之后&#xff0c;要在Mainform调用自己写的Form。 如果按照正常的Form form1 new For…

MIT 6.824 -- MapReduce -- 01

MIT 6.824 -- MapReduce -- 01 引言抽象和实现可扩展性可用性(容错性)一致性MapReduceMap函数和Reduce函数疑问 课程b站视频地址: MIT 6.824 Distributed Systems Spring 2020 分布式系统 推荐伴读读物: 极客时间 – 大数据经典论文解读DDIA – 数据密集型应用大数据相关论文…

【具身智能】系列论文解读(CoWs on PASTURE VoxPoser Relational Pose Diffusion)

0. My Conclusion CoWs on PASTURE&#xff1a; 擅长零样本的视觉语言对象导航&#xff0c;主要解决了LLM辅助下的任务级动作执行任务VoxPoser&#xff1a; 擅长设计一些未预定义的动作轨迹&#xff0c;主要解决了LLM辅助下的动作轨迹设计任务Relational Pose Diffusion&#…

Packet Tracer - 将路由器连接到 LAN

Packet Tracer - 将路由器连接到 LAN 地址分配表 设备 接口 IP 地址 子网掩码 默认网关 R1 G0/0 192.168.10.1 255.255.255.0 N/A G0/1 192.168.11.1 255.255.255.0 N/A S0/0/0 (DCE) 209.165.200.225 255.255.255.252 N/A R2 G0/0 10.1.1.1 255.255.255…

概率论与数理统计复习总结3

概率论与数理统计复习总结&#xff0c;仅供笔者复习使用&#xff0c;参考教材&#xff1a; 《概率论与数理统计》/ 荣腾中主编. — 第 2 版. 高等教育出版社《2024高途考研数学——概率基础精讲》王喆 概率论与数理统计实际上是两个互补的分支&#xff1a;概率论 在 已知随机…

Kernel Exception导致手机重启案例分析

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、高温触发 Kernel Exception 重启问题二、解决方案三、提高电池温度方案 一、 高温触发 Kernel Exception 重启问题 手机 电池温度 默认60度以上高温…

CBCGPRibbon 添加背景图片

resource.h中声明资源的ID&#xff1a;ID_RIBBON_BACKIMAGE rc文件中添加png图片路径&#xff1a; ID_RIBBON_BACKIMAGE PNG DISCARDABLE "res\\bkribbon.png" 代码中添加下测&#xff1a; //添加背景图片 m_wndRibbonBar.SetBackgroundImage(ID_RIB…

C语言单链表OJ题(较易)

一、移除链表元素 leetcode链接 题目描述&#xff1a; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 思路&#xff1a; 正常遍历&#xff0c;找到value的值与题目中相同的结点去fr…

第5集丨Vue 江湖 —— 监视属性/侦听属性

目录 一、基本使用1.1 watch配置监视1.2 vm.$watch动态监视1.3 深度监视(deep watch)1.4 简写形式 二、computed和watch的对比2.1 使用watch实现setTimeout操作2.2 用computed无法实现setTimeout 三、其他注意事项3.1 vue devtools的bug3.2 xxxyyy格式3.3 将window传入data中 V…

机器人开发--富锐雷达介绍

机器人开发--富锐雷达介绍 1 介绍参考 1 介绍 山东富锐光学科技有限公司是一家专注智能感知领域的激光雷达公司&#xff0c;致力于激光雷达前沿技术的开发和应用。 公司已累计完成数亿元融资&#xff0c;依托潍坊光电产业发展基础&#xff0c;自建生产线&#xff0c;达到年产…

LNMP安装

目录 1、LNMP简述&#xff1a; 1.1、概述 1.2、LNMP是一个缩写词&#xff0c;及每个字母的含义 1.3、编译安装与yum安装差异 1.4、编译安装的优点 2、通过LNMP创建论坛 2.1、 安装nginx服务 2.1.1、关闭防火墙 2.1.2、创建运行用户 2.1.3、 编译安装 2.1.4、 优化路…

Portraiture 4.0.3 for windows/Mac简体中文版(ps人像磨皮滤镜插件)

Imagenomic Portraiture系列插件作为PS磨皮美白必备插件&#xff0c;可以说是最强&#xff0c;今天它更新到了4.0.3版本。但是全网都没有汉化包&#xff0c;经过几个日夜汉化&#xff0c;终于汉化完成可能是全网首个Portraiture 4的汉化包&#xff0c;请大家体验&#xff0c;有…