算法通过村第六关-树白银笔记|层次遍历
文章目录
- 前言
- 1. 层次遍历介绍
- 2. 基本的层次遍历与变换
- 2.1 二叉树的层次遍历
- 2.2 层次遍历-自底向上
- 2.3 二叉树的锯齿形层次遍历
- 2.4 N叉树的层次遍历
- 3. 几个处理每层元素的题目
- 3.1 在每棵树行中找出最大值
- 3.2 在每棵树行中找出平均值
- 3.3 二叉树的右视图
- 3.4 最底层最左边
- 总结
前言
提示:这个世界上的任何一次拥抱都是将以松手告终。 --约瑟夫·布罗茨基《悲伤与理智》
二叉树的层次遍历是一个非常简单的问题,但是很多人没有接触过,所以就认为很难,面试的时候当然就写不出来了,今天我们就重点通关层次遍历这个问题。
1. 层次遍历介绍
广度优先在面试中属于常考类型,整体来说属于简单次,但是很多人面试遇到了就放弃,真的很可惜。我们就看看它的难度在哪里。
广度优先又叫做层次遍历,基本过程如下:

层次遍历就是从根节点开始,先访问根节点的一层全部元素,在访问之后的一层,类似金字塔一样一层一层访问。我们可以看做就是从左到右的一层一层去遍历二叉树,先访问5,之后访问3的左右孩子4 和 6 ,之后再访问4 和 6的孩子1 2 和 7 8。最后得到结果【5,4,6,1,2,7,8】
这里的问题就变成了将遍历过的子孩子保存下来,比如访问4 的左右孩子1 和 2 的时候应该先存储,直到处理完20之后再处理。使用队列的话就可以解决上述问题。
看下过程图解:
- 根节点入队 5
- 然后 5 出队, 之后将 5 的左右孩子4 6入队,保存在队列中
- 4 出队,将4 的左右孩子 1 2 入队
- 之后 6 出队,将 6 的左右孩子 7 8 入队,保存在队列中
- 最终 1 2 7 8 依次出队,此时都是叶子几点,只要出队就行了。
这个过程不复杂,如果将树的每层分开,是不是可以整活😎了?首先,能否将每层的元素顺序反转一下?或者说奇数不变,偶数反转?是否将输出层次从低到高(root)输出呢?再比如,既然可以拿到每层的元素,能不能找到当前层最大的元素?最小的元素呢?最右端的元素(右视图)?最左端的元素(左视图)?整个层的平均值?当然这都是可以实现的嘞😋,这么来回折腾有啥用呢?🤔,没啥用了,但是这些都是层次遍历的高频算法题目。
推荐力扣题目⭐⭐⭐⭐:
102. 二叉树的层序遍历 - 力扣(LeetCode)
107. 二叉树的层序遍历 II - 力扣(LeetCode)
199. 二叉树的右视图 - 力扣(LeetCode)
637. 二叉树的层平均值 - 力扣(LeetCode)
429. N 叉树的层序遍历 - 力扣(LeetCode)
515. 在每个树行中找最大值 - 力扣(LeetCode)
116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode)
117. 填充每个节点的下一个右侧节点指针 II - 力扣(LeetCode)
103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode)
2. 基本的层次遍历与变换
我们看一个最简单的情况,仅仅是遍历并输出全部元素,如下图:

上图的输入结果【5,4,6,7,8】,方法已经梳理过了,这里看一下代码怎么实现。先访问根节点,然后其左右孩子入队,接着出队,出队的元素将其左右孩子入队,直到队列为空就可以退出了:
/*** 二叉树层序遍历* @param root* @return*/public static List<Integer> simpleLevelOrder(TreeNode root) {// 参数校验if (root == null) {return new ArrayList<Integer>();}// 创建存储空间List<Integer> res = new ArrayList<Integer>();LinkedList<TreeNode> queue = new LinkedList<TreeNode>();// 根节点先入队queue.add(root);// 遍历队列元素while(queue.size() > 0){// 获取当前队列的长度,这个长度相当于这一层的节点个数TreeNode t = queue.remove();res.add(t.val);if (t.left != null){queue.add(t.left);}if (t.right != null){queue.add(t.right);}}return res;}
注意:
根据树的结构可以看出,一个节点在一层访问之后,其子孩子都是在下层按照FIFO的顺序处理的,因此队列在这里起到了一个缓存的作用。
如果要你将每层的元素分开该怎么做呢?看下下面的这个题:
2.1 二叉树的层次遍历
题目介绍:102. 二叉树的层序遍历 - 力扣(LeetCode)


我们再来看这个执行过程,我们先将根节点放入队列中,然后不断的遍历队列。

那如何判断某一层访问完了呢?这个简单,我们用一个size标记一下就行了,size表示某一层元素的个数,知道出队,size就减1,减到0就说明该层访问完了,当size变成0之后,这时队列中甚于元素个数恰好就是下一次的个数,因此重新将size标记为下一层的元素个数就可以继续处理新的一行,例如上面的序列中:
- 首先获取根节点 3 ,左右子节点不为空,将左右子节点放入队列,此时3 已经出队。剩下的9 20 恰好是第二层的所有节点,此时size = 2
- 继续将9 出队,左右节点不为空,将左右节点放入队列,size-- ,变成 1 ,之后将20 出队,左右节点不为空,将左右节点放入队列 size–, 变为 0。当size = 0,说明当前层已经处理完了,此时队列有4个元素,恰好是下一层的元素个数。
- 最后,我们把每层遍历到的节点放入一个结果集中,将其返回就可以了
按层次遍历经典代码:
/*** 层次遍历 经典方式* @param root* @return*/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.size() > 0){// 获取当前size的个数 即当前层有多少个元素int size = queue.size();// 创建临时空间 将一层的元素存入其中List<Integer> temp = new ArrayList<Integer>();for(int i = 0; i < size; i++){TreeNode t = queue.remove();temp.add(t.val);if (t.left != null){queue.add(t.left);}if (t.right != null){queue.add(t.right);}}// 此时的temp就是一层的所有元素,用list类型保存temp,最后加入到结果集中res.add(temp);}return res;}
此方法一定要牢记,在算法体系中是很重要的一环,他与链表反转,二分查找可以相提并论,务必掌握,彻底理解,然后记忆。
当然上面的算法理解了,下面的一系列题目都变得简单了,不信你往下看。
注意:
在Java中队列的实现不止一种,需要注意。
2.2 层次遍历-自底向上
题目介绍:107. 二叉树的层序遍历 II - 力扣(LeetCode)


如果要求从上到下输出每一层的节点值,做法很直观,在遍历完一层之后,将该层存储节点值的列表添加到结果集的尾部。这道题要求从下到上输出每一层的节点值,只要对上述操作稍作修改就可以了,在遍历完一层节点后,将存储该层节点值的列表添加到结果集的头部。
为了降低在结果列表的头部添加一层节点值的列表的时间复杂度,结果列表可以使用链表的结构,在链表头部添加一层节点值的列表的时间复杂度为O(1),在Java中,由于我们需要返回一个List接口,在这里可以使用链表实现。
代码就很普通了😎:
/*** 层序遍历 自底向上* @param root* @return*/public static List<List<Integer>> levelOrderBottom(TreeNode root) {// 校验参数if (root == null){return new ArrayList<List<Integer>>();}// 创建空间List<List<Integer>> levelOrder = new LinkedList<List<Integer>>();Queue<TreeNode> queue = new LinkedList<TreeNode>();// 根节点存入队列中 不断的遍历queue.offer(root);while(queue.size() > 0){List<Integer> level = new ArrayList<Integer>();int size = queue.size();for(int i = 0; i < size; i++){TreeNode node = queue.poll();level.add(node.val);// 这样也行TreeNode left = node.left,right = node.right;if(left != null){queue.offer(left);}if (right != null){queue.offer(right);}}levelOrder.add(0,level); // 放在头部 栈}return levelOrder;}
2.3 二叉树的锯齿形层次遍历
题目介绍:103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode)


这个题也是102. 二叉树的层序遍历 - 力扣(LeetCode)的变种,只是最后输出的要求变化了,要求我们按照层数的奇偶来决定每层输出的顺序,如果当前是偶数层,从左到右输出当前层的节点值,否则,从右至左输出当前层的节点值。这里我们同样可以采用102的方法思想。
但是为了满足条件,【左右->右左】交替暑促的锯齿形,可以利用【双端队列】的数据机构来维护当前节点值的输出顺序。双端队列是一个可以在队列任意一端插入元素的队列。在广度优先遍历搜索当前节点,扩展下一层节点的时候我们仍然可以从左往右循序扩展,但是对于当前层节点的存储我们维护一个变量isOrderLeft记录时从左到右还是从右到左:
- 如果从左到右,我们每次将被遍历的元素插入到双端队列的末尾
- 从右到左,我们每次将被遍历的元素插入到双端队列的头部。
代码展示😋
/*** 锯齿层次遍历* @param root* @return*/public static List<List<Integer>> zigzagLevelOrder(TreeNode root) {// 校验参数if (root == null){return new ArrayList<List<Integer>>();}// 创建空间List<List<Integer>> ans = new LinkedList<List<Integer>>();Queue<TreeNode> queue = new LinkedList<TreeNode>();// 将根节点放入队列 不断循环遍历queue.offer(root);// 判断奇偶变量boolean isOrderLeft = true;while(queue.size() >0){// 这里要使用双端队列Deque<Integer> temp = new LinkedList<Integer>();int size = queue.size();for(int i = 0; i < size; i++){TreeNode t = queue.poll();if (isOrderLeft){temp.offerLast(t.val);}else{temp.offerFirst(t.val);}if (t.left != null){queue.offer(t.left);}if (t.right != null){queue.offer(t.right);}}ans.add(new LinkedList<Integer>(temp));isOrderLeft = !isOrderLeft;}return ans;}
2.4 N叉树的层次遍历
题目介绍:429. N 叉树的层序遍历 - 力扣(LeetCode)


首先看下N叉树的结构,就是一个值的不同,变成了以一个列表,其类型仍然时Node:
class TreeNode {public int val;public List<TreeNode> children;}
也就是说我们可以说,这个也是102. 二叉树的层序遍历 - 力扣(LeetCode)的变种,我们就用简单的广度优先,借助队列即可实现。
/*** N 叉树的遍历* @param root* @return*/public static List<List<Integer>> nLevelOrder(NTreeNode root) {// 校验参数if (root == null){return new ArrayList<List<Integer>>();}// 创建空间List<List<Integer>> res = new ArrayList<List<Integer>>();Deque<NTreeNode> queue = new ArrayDeque<NTreeNode>();// 根节点放入队列 不断遍历queue.offer(root);while(!queue.isEmpty()){Deque<NTreeNode> next = new ArrayDeque<>();List<Integer> level = new ArrayList<>();while(!queue.isEmpty()){NTreeNode current = queue.pollFirst();level.add(current.val);// 注意这里链表遍历for (NTreeNode child : current.children){if (child != null){next.add(child);}}}// 重新定义queuequeue = next;res.add(level);}return res;}
3. 几个处理每层元素的题目
如果我们拿到每一层的元素,那么是不是可以利用一下就可以造几个题目出来呢?例如每层找最大的值,平均值,最右侧的值?当然可以。这也是力扣的上面比较经典的题目了:
题目推荐⭐⭐⭐⭐:
515. 在每个树行中找最大值 - 力扣(LeetCode)
637. 二叉树的层平均值 - 力扣(LeetCode)
199. 二叉树的右视图 - 力扣(LeetCode)
当然我们自己也可以造题目,比如说层次取最小值可以吗?每层的最左侧值可以不?是不是现在发现算法其实很好玩的🥰
3.1 在每棵树行中找出最大值
题目介绍:515. 在每个树行中找最大值 - 力扣(LeetCode)

这里其实就是得到一层之后使用一个变量来记录当前的最大值:
代码也很简单:
/*** 层序遍历找到每层最大值* @param root* @return*/public static List<Integer> largestValues(TreeNode root) {// 校验参数if(root == null){return new ArrayList<Integer>();}// 创建空间List<Integer> res = new ArrayList<Integer>();Deque<TreeNode> queue = new ArrayDeque<TreeNode>();// 根节点入队,不断循环遍历queue.offer(root);while(queue.size() > 0){int size = queue.size();int maxLevel = Integer.MIN_VALUE;for(int i = 0; i < size; i++){TreeNode t = queue.poll();maxLevel = Math.max(maxLevel, t.val);if (t.left != null){queue.offer(t.left);}if (t.right != null){queue.offer(t.right);}}res.add(maxLevel);}return res;}
3.2 在每棵树行中找出平均值
题目介绍:637. 二叉树的层平均值 - 力扣(LeetCode)


这个题目和前面的一样,之不多每层都先将元素保存下来,最后求一个平均值就可以了,是不是是很简单;
/*** 层序遍历,求出每层平均值* @param root* @return*/public static List<Double> averageOfLevels(TreeNode root) {// 检验参数if(root == null){return new ArrayList<Double>();}// 创建空间List<Double> res = new ArrayList<Double>();Queue<TreeNode> queue = new LinkedList<TreeNode>();// 根节点入队,不断循环queue.offer(root);while(queue.size() > 0){int size = queue.size();double sum = 0;for(int i = 0; i < size; i++ ){TreeNode t = queue.poll();sum += t.val;if (t.left != null){queue.offer(t.left);}if (t.right != null){queue.offer(t.right);}}res.add(sum/size);}return res;}
3.3 二叉树的右视图
题目介绍:199. 二叉树的右视图 - 力扣(LeetCode)


这个题目说实话出频率还挺高的,如果没有提前思考过,很难想到答案。其实也简单,在BFS进行层次遍历的时候,记录下每层的最后一个元素就可以了。
/*** 层序遍历,输出右视图* @param root* @return*/public static List<Integer> rightSideView(TreeNode root) {// 校验参数if(root == null){return new ArrayList<Integer>();}// 创建空间List<Integer> res = new ArrayList<Integer>();Queue<TreeNode> queue = new LinkedList<TreeNode>();// 根节点入队,不断循环遍历queue.offer(root);while(!queue.isEmpty()){int size = queue.size();for(int i = 0; i < size; i++){TreeNode t = queue.poll();if (t.left != null){queue.offer(t.left);}if (t.right != null){queue.offer(t.right);}// 这里将最后一个节点放入结果集中if (i == size - 1){res.add(t.val);}}}return res;}
是不是有点成就感了,感觉算法是有套路的,并不是四刷题目。这三道题基本上都是层序遍历的变种。
那我我们也可以尝试着造出题目来:
有右视图,那么左视图行不行?俯视图行不行?想一下💡
嘿嘿😁,我这里告诉你吧,俯视图不行,但是左视图可以,想下为什么?🤔
3.4 最底层最左边
题目介绍:513. 找树左下角的值 - 力扣(LeetCode)


在第二部分,我们写了很多层次遍历的变种形式,这里有两个问题:
- 该怎么知道什么时候到最底层了?
- 加入最底层有两个,该怎么知道那个时最左的呢?
带着这两个问题,我们再看下层序遍历的执行过程:

我们可以发现,正常执行层次遍历的,不管最底层有几个元素,最后输出的一定是底层最右的元素7,这里我们就想象一下,可不可以和上面题目一样结合反转操作实现呢,每一层先反转再存入队列,到最后是不是输出的为最左节点值呢?是的,知道了这个解题关键点,我想答案你已经会写了🥰。
public int findBottomLeftValue(TreeNode root) {// 校验参数if(root.left == null && root.right == null){return root.val;}// 创建空间Queue<TreeNode> queue = new LinkedList<TreeNode>();// 根节点入队,不断循环遍历queue.offer(root);TreeNode temp = new TreeNode();while(!queue.isEmpty()){temp = queue.poll();// 先右后左 if(temp.right != null){queue.offer(temp.right);}if(temp.left != null){queue.offer(temp.left);}}return temp.val;}
总结
提示:二叉树的层序遍历,各种变种问题,熟练掌握模板题,总结套路,是不是感觉算法也是有迹可循的😎
相关文章:
算法通过村第六关-树白银笔记|层次遍历
文章目录 前言1. 层次遍历介绍2. 基本的层次遍历与变换2.1 二叉树的层次遍历2.2 层次遍历-自底向上2.3 二叉树的锯齿形层次遍历2.4 N叉树的层次遍历 3. 几个处理每层元素的题目3.1 在每棵树行中找出最大值3.2 在每棵树行中找出平均值3.3 二叉树的右视图3.4 最底层最左边 总结 前…...
SpringCloud理解篇
一、微服务概述 1、什么是微服务 目前的微服务并没有一个统一的标准,一般是以业务来划分将传统的一站式应用,拆分成一个个的服务,彻底去耦合,一个微服务就是单功能业务,只做一件事。 与微服务相对的叫巨石 。 2、微服…...
编写LED灯的驱动,实现三盏灯的控制
mychrdev.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include "head.h"unsigned int major; // 保存主设备号 char kbuf[128]{0}; unsigned int…...
Flink报错处理-1
在 flink job 运行一段时间后,观察日志发现出现了如下的 warn日志: The operator name {} exceeded the {} characters length limit and was truncated 完整的 warn 日志如下: The operator name TriggerWindow(GlobalWindows(), ListStat…...
bim与数字孪生智能建造的关系
随着建筑业数字化改革的推进,我们正迈入数字孪生时代,而真正实现建筑物数字孪生的智能建造,其基础前提是建造对象和建造过程的高度数字化,这样一个过程唯有依托BIM建立数据模型才能实现,真正达到智能建造或智慧运维。 …...
【Linux】进程篇(补):守护进程
文章目录 1. 补充1.1 查看1.2 控制进程组的方式 2. 创建守护进程step1. 忽略信号step2. 让自己不是组长step3. setsid 函数:给调用函数设置新的会话和进程组 IDstep4. chdir 函数:可以改变守护进程的工作路径step5. 处理文件描述符 0、1、2 守护进程类样…...
SpringMVC自定义视图完成步骤 和 视图解析的源码剖析
自定义视图完成步骤: ● 7.2.1自定义视图完成步骤 1. 自定义视图**:** 创建一个 View 的 bean, 该 bean 需要继承自 AbstractView, 并实现 renderMergedOutputModel 方法**.** 2. 并把自定义 View 加入到 IOC 容器中 3. 自定义视图的视图处理器,使用…...
合宙Air724UG LuatOS-Air lvgl字库
目录 LVGL 简介1. lvgl自带字库 特点使用场景2. lvgl加载外部字体 软件接口使用场景3. lvgl 矢量字体 软件接口硬件外接SPI字库芯片详细使用示例使用场景常见问题 LVGL 简介 LVGL字库有3种方式可以使用,刚接触的客户可能不太了解怎样选用,以下对这3种…...
C#,数值计算——指数微分(exponential deviates)的计算方法与源程序
1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 指数偏差 /// Structure for exponential deviates. /// </summary> public class Expondev : Ran { private double beta { get; set; } /// <s…...
ADAS自动驾驶
文章目录 ADAS技术现状ADAS功能的主流方案ADAS控制器开发自动驾驶技术现状自动驾驶域控制器开发智能驾驶域控制器芯片选择 ADAS技术现状 自动驾驶辅助系统(ADAS,Advanced Driver Assistance Systems)是一种用于提高驾驶安全和舒适性的技术&a…...
Python从零到一构建项目
随着互联网的发展,网络上的信息量急剧增长,而获取、整理和分析这些信息对于很多人来说是一项艰巨的任务。而Python作为一种功能强大的编程语言,它的爬虫能力使得我们能够自动化地从网页中获取数据,大大提高了效率。本文将分享如何…...
使用todesk或者向日葵远程Ubuntu22.04系统的客户机黑屏
[TOC](使用todesk或者向日葵远程Ubuntu22.04系统的客户机黑屏) 目录 1. 故障现象 2. 分析 3. 解决办法 4. 参考文章 1. 故障现象 使用todesk或者向日葵远程客户机(Ubuntu22.04系统)时,显示黑屏 2. 分析 本故障可能是因为Ubuntu22.04的图…...
JBoss JMXInvokerServlet 反序列化漏洞复现(CVE-2015-7501)
一、漏洞说明 JBoss中/invoker/JMXInvokerServlet路径对外开放,JBoss的jmx组件支持反序列化。JBoss在/invoker/JMXInvokerServlet请求中读取了用户传入的对象,然后我们利用Apache Commons Collections中的Gadget执行任意代码。 二、影响版本 JBoss Enter…...
比Mojo慢68000倍,Python性能差的锅该给GIL吗?
# 关注并星标腾讯云开发者 # 每周1 | 鹅厂工程师带你审判技术 # 第3期 | 李志瑞:天使还是魔鬼?聊聊 Python GIL 9 月 7 日,新兴编程语言 Mojo 正式发布。Mojo 的最初设计目标是比 Python 快 35000 倍,近期该团队表示,因…...
CSS读书笔记
——————————————精华部分—————————————— 1、选择器 (1)基本选择器: 标签选择器 body{} 类选择器 class .class名称{} ID选择器 id #id名称{} 优先级:ID选择器 > 类选择器 > 标签选择器 &am…...
Qt使用QSqlDatabase remoeDatabase()连接提示仍在使用解决方案
问题描述 调用QSqlDatabase的removeDatabase函数的时候,出现了如下错误 QSqlDatabasePrivate::removeDatabase: connection 05465461654654 is still in use, all queries will cease to work官方示例 [static] void QSqlDatabase::removeDatabase(const QString &…...
管易云与金蝶云星空对接集成仓库查询打通仓库新增
管易云与金蝶云星空对接集成仓库查询打通仓库新增 接通系统:管易云 管易云是金蝶旗下专注提供电商企业管理软件服务的子品牌,先后开发了C-ERP、EC-OMS、EC-WMS、E店管家、BBC、B2B、B2C商城网站建设等产品和服务,涵盖电商业务全流程。 对接目…...
ubuntu 安装 Mongodb 4.0、4.2、4.4
1. 安装 # 配置apt Repository mongodb 4.0, 4.2, 4.4 $ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 68818c72e52529d4 #4.0 $ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 4B7C549A058F8B6B #4.2 $ …...
详解Hugging Face Transformers的TrainingArguments
前言: TrainingArguments是Hugging Face Transformers库中用于训练模型时需要用到的一组参数,用于控制训练的流程和效果。 使用示例: from transformers import Trainer,TrainingArguments training_args TrainingArguments(output_dir&q…...
【LeetCode-中等题】17. 电话号码的字母组合
文章目录 题目方法一:递归回溯 题目 方法一:递归回溯 参考讲解:还得用回溯算法!| LeetCode:17.电话号码的字母组合 首先可以画出树图: 先将数字对应的字符集合 加入到一个map集合 这里需要一个index来控…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
