层序遍历?看这一篇就够了!

article/2025/9/18 19:45:01

点关注不迷路

1.树的层序遍历

顾名思义,对于树型结构,层序遍历就是按层从上到下,每层按一定顺序对树的节点进行遍历。我们通过如图所示的二叉树进行说明:对于左边的二叉树,按层划分后可得到右边的分层结构。

如果按照每层从左到右的遍历逻辑,这棵二叉树的层序遍历序列就是 [ 1 , 4 , 2 , 7 , 20 , 5 ] [1, 4, 2, 7, 20, 5] [1,4,2,7,20,5]。通过代码如何实现呢?一般地,我们利用队列 q u e u e queue queue 作为容器,按照如下逻辑进行遍历:

// 0. 声明队列
queue<TreeNode*> q;
// 1. 将根节点加入队列
q.push(root);
// 2. 遍历队列中每个节点
while(!q.empty()) {TreeNode* cur = q.front();q.pop();// 3. 记录当前节点值vec.push(cur->val);// 4. 将左右孩子放入队列q.push(cur->left);q.push(cur->right);
}

同一层中的节点自左向右遍历是通过队列实现的:还是拿之前的例子来说,先将值为 1 1 1 的节点放入队列,然后将先左孩子 4 4 4 放入队列,再将右孩子 2 2 2 放入队列,由于队列是先进先出型结构,所以保证了值为 4 4 4 的节点要先于值为 2 2 2 的孩子处理;同样地,第三层节点放入队列的顺序依次为 7 , 20 , 5 7, 20, 5 7,20,5,与之后的处理顺序相同,保证了从左向右的顺序。过程如下图所示:(黄色代表加入队列的节点、粉色代表当前处理的节点、蓝色表示吃瓜的节点)

1

2

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一般地,在遍历完第 k k k 层的最后一个节点后,该层所有节点都被弹出了队列,且其孩子节点(均处于 k + 1 k + 1 k+1 层)都被存入了队列且未处理,所以当前队列的长度就是 k + 1 k + 1 k+1 层的节点数量。

所以,通过提前记录队列长度,可以方便地应对一些需要对各层进行特殊处理的问题。

特别地,为了防止二叉树为空、遍历到叶节点等情况,需要加入一些特判元素。修改后的模板如下:

// 1.初始化
queue<TreeNode*> q;
if(root == NULL) { // 二叉树为空return;
}
q.push(root);// 2.遍历整棵树
while(1) {int cnt = q.size(); // 要处理层的节点个数if(cnt == 0) break; // 已经遍历完二叉树// 3.遍历该层while(cnt--) {TreeNode* cur = q.front();q.pop();// 4.对 cur 的操作,根据题意更改action(cur);// 5.将左右孩子放入队列if(cur->left) q.push(cur->left);if(cur->right) q.push(cur->right);}
}

点关注不迷路

2.几道例题

说明:对于不同的题目,只需要在我们的模板基础上增加或更改一些元素,所以对于下面的每道例题,我们在代码中只重点注释修改的部分。

第一题:二叉树的层序遍历

我们先从基础的力扣102题来入手:题目要求返回一个二维容器,其中的每一个容器记录着某一层的所有节点值。我们只需要层序遍历二叉树,并按层遍历节点,将其加入 v e c t o r vector vector。在遍历完该层后,将记录了该层所有节点的 v e c t o r vector vector 加入结果容器即可,代码如下:

  vector<vector<int>> levelOrder(TreeNode* root) {// 声明结果二维容器vector<vector<int>> result;queue<TreeNode*> q;if(root == NULL) return result;q.push(root);while(1) {int cnt = q.size();if(cnt == 0) break;// 记录该层节点的容器vector<int> v;while(cnt--) {TreeNode* cur = q.front();q.pop();// 将当前节点存入容器v.push_back(cur->val);if(cur->left) q.push(cur->left);if(cur->right) q.push(cur->right);}// 处理完该层,加入结果容器result.push_back(v);}return result;}

第二题:二叉树的层序遍历 II

与上一道题不同,要求从下到上遍历。实际上我们只需要从上向下遍历后,将结果容器翻转即可。C++的标准库STL给我们提供了容器翻转的函数:
r e v e r s e ( r e s u l t . b e g i n ( ) , r e s u l t . e n d ( ) ) reverse(result.begin(), result.end()) reverse(result.begin(),result.end())

第三题:二叉树的锯齿形层序遍历

与前两题不同,对于给定的如图所示的树,锯齿形遍历需要偶数层从右向左返回结果,奇数层从左向右返回结果,也即返回的结果序列应为:

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

本质上,我们只需要翻转偶数层的容器,就可以把从左向右的遍历转化为从右向左的遍历。在代码实现时,我们增加一个布尔型变量,记录当前层是否需要翻转,并每层将该变量取反即可:

vector<vector<int>> zigzagLevelOrder(TreeNode* root) {vector<vector<int>> result;// 当前层是否需要翻转bool flag = false;queue<TreeNode*> q;if(root == NULL) return result;q.push(root);while(1) {int cnt = q.size();if(cnt == 0) break;vector<int> v;while(cnt--) {TreeNode* cur = q.front();q.pop();v.push_back(cur->val);if(cur->left) q.push(cur->left);if(cur->right) q.push(cur->right);}// 判断是否翻转if(flag) reverse(v.begin(), v.end());result.push_back(v);// 取反flag = !flag;}return result;
}

第四题:二叉树的最大深度

这是力扣第104题,在我们的模板里,每处理完一层,才退出内层循环,并开始新一轮外层循环。而本题要找最大深度,就是找一共处理了多少层,所以提前维护一个记录层数的变量 d e p t h depth depth,然后在外层循环内每次增加该变量即可:

int maxDepth(TreeNode* root) {int depth = 0; // 声明深度queue<TreeNode*> q;if(root == NULL) return 0;q.push(root);while(1) {int cnt = q.size();if(cnt == 0) break;depth++; // 处理新一层前深度自加while(cnt--) {TreeNode* cur = q.front();q.pop();if(cur->left) q.push(cur->left);if(cur->right) q.push(cur->right);}}return depth;
}

特别地, d e p t h + + depth++ depth++ 语句必须要放在判断 c n t = 0 cnt = 0 cnt=0 的语句之后,否则若遍历到最后一层,深度自加之后才会退出循环,导致结果错误。

第五题:二叉树的最小深度

第111题要求“最小深度”(找到离根节点最近的叶子节点),由于我们进行的是层序遍历,只要找到一个叶子节点,该节点就一定是所求的最近节点。所以,遍历过程中增加判断叶子节点的部分即可。来看看代码:

int minDepth(TreeNode* root) {int depth = 0;queue<TreeNode*> q;if(root == NULL) return 0;q.push(root);while(1) {int cnt = q.size();if(cnt == 0) break;depth++;while(cnt--) {TreeNode* cur = q.front();q.pop();// 叶子节点if(!cur->left && !cur->right) return depth;if(cur->left) q.push(cur->left);if(cur->right) q.push(cur->right);}}return depth;
}

最后总结

层序遍历的关键,要明确每一轮循环的具体过程。二叉树遍历相关的算法题,都是基于层序遍历框架的,我们只要搞清楚 r o o t root root 节点本身要做什么,根据题目要求进行处理,再把左右孩子往队列里一放就行了。

如果本文讲的层序遍历对你有一些启发,请三连支持作者~~~

推荐阅读

点关注不迷路


http://chatgpt.dhexx.cn/article/wEHn9vHA.shtml

相关文章

二叉树遍历——层序遍历

目录 1.什么是层序遍历&#xff1f; 2.实现思路 3.代码实现 1.什么是层序遍历&#xff1f; 就是将一颗树按照每一层每一层的方式进行遍历 例如这棵树&#xff0c;进行层序遍历的结果应该是 那么我们该怎样去实现呢&#xff1f; 2.实现思路 利用队列先进先出的思想去实现 …

【二叉树 Java】二叉树的层序遍历

一、层序遍历定义&#xff1a; 按照每层进行遍历&#xff0c;从左至右&#xff0c;从上至下遍历树的节点&#xff0c;如下图所示 二、题目描述&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所…

二叉树----层序遍历

1.层序遍历 层序遍历:层序遍历即逐层按顺序遍历二叉树的各个节点,故层序遍历又叫广度优先遍历. 如图:广度优先遍历即按ABCDEFGH的顺序遍历 2.解题思路 1.这里我们利用队列先进先出的结构特点,当我们在队列中弹出一个树的节点时,我们便把树的左孩子和右孩子入到队列之中.(如果父…

二叉树的层序遍历

二叉树的层序遍历 1.层序遍历2.实例2.1二叉树的层序遍历2.2 二叉树的层序遍历 II2.3 二叉树的右视图2.4 二叉树的层平均值2.5 N叉树的层序遍历2.6在每个树行中找最大值2.7二叉树的最大深度2.8二叉树的最小深度2.9翻转二叉树2.10完全二叉树的节点个数2.11左叶子之和2.11找树左下…

二叉树的遍历——层序遍历

一、之前写了二叉树的三种遍历方法&#xff1a;有先序遍历、中序遍历、后序遍历&#xff0c;这三种方法都是用递归的方式来遍历二叉树的。层序遍历则不是使用递归来遍历&#xff0c;而是使用队列的来实现遍历&#xff1a; void LevelTreeOrder(BTNode* root) {Queue q;QueueIni…

【机器学习】LDA算法 (主题模型算法)

随着互联网的发展&#xff0c;文本分析越来越受到重视。由于文本格式的复杂性&#xff0c;人们往往很难直接利用文本进行分析。因此一些将文本数值化的方法就出现了。LDA就是其中一种很NB的方法。 LDA有着很完美的理论支撑&#xff0c;而且有着维度小等一系列优点。本文对LDA算…

LDA算法和PCA算法的总结(原理和思想)

LDA和PCA的对比(并没有公式推导&#xff0c;改日会写) 先补一补数学(不需要)&#xff1a; 方差——概率论和统计方差衡量随机变量或一组数据时离散程度的度量&#xff1b;概率论中方差用来度量随机变量和其数学期望之间的偏离程度。统计中的方差&#xff08;样本方差&#xff…

LDA算法原理及LDA与PCA的比较

1. LDA算法简介 LDA&#xff08;线性判别式分析 Linear Discriminant Analysis&#xff09;属于机器学习中的监督学习算法&#xff0c;常用来做特征提取、数据降维和任务分类。在人脸识别、人脸检测等领域发挥重要作用。LDA算法与PCA算法都是常用的降维技术。二者的区别在于&a…

LDA算法调研报告

LDA算法调研报告 1、LDA算法概述 本文所阐述的LDA算法全称为Latent Dirichlet Allocation&#xff08;网上没有标准的中文名称&#xff0c;我称之为潜在狄利克雷分配算法&#xff09;&#xff0c;不是线性判别分析算法&#xff08;Linear Discriminant Analysis&#xff09;。L…

【机器学习】LDA算法原理

问题 线性判别分析(Linear Discriminant Analysis,LDA)是机器学习中常用的降维方法之一,本文旨在介绍LDA算法的思想,其数学推导过程可能会稍作简化。 LDA的思想 ● LDA是一种线性的、有监督的降维方法,即每个样本都有对应的类别标签(这点和PCA不同)。 ● 主要思想:…

Spark机器学习-LDA算法09

LDA算法 LDA即文档主题生成模型,该算法是一种无监督学习 将主题对应聚类中心,文档作为样本,则LDA也是一种聚类算法 该算法用来将多个文档划分为K个主题,与Kmeans类似 LDA是一种基于概率统计的生成算法 LDA算法—种常用的主题模型,可以对文档主题进行聚类,同样也可以用…

LDA算法实现鸢尾花数据集降维

目录 1. 作者介绍2. LDA降维算法2.1 基本概念2.2 算法流程 3. LDA算法实现3.1 数据集介绍3.2 代码实现3.3 结果展示 1. 作者介绍 唐杰&#xff0c;男&#xff0c;西安工程大学电子信息学院&#xff0c;2022级研究生 研究方向&#xff1a;机器视觉与人工智能 电子邮件&#xff…

秒懂---LDA算法

线性判别分析LDA原理总结 在主成分分析&#xff08;PCA&#xff09;原理总结中&#xff0c;我们对降维算法PCA做了总结。这里我们就对另外一种经典的降维方法线性判别分析&#xff08;Linear Discriminant Analysis, 以下简称LDA&#xff09;做一个总结。LDA在模式识别领域&…

基于Sklearn实现LDA算法

文章目录 一、LDA算法二、sklearn实现LDA三、结果如图四、总结五、参考 一、LDA算法 1.线性判别分析&#xff08;Linear Discriminant Analysis, LDA&#xff09;方法常被用于数据预处理中的降维&#xff08;dimensionality reduction&#xff09;步骤。LDA在保证良好的类别区…

LDA算法推导

LDA算法是什么 简单地说LDA算法就是向低维度投影&#xff0c;让同一类别数据投影点更接近&#xff0c;不同类别数据点距离更远。 LDA原理 定义&#xff0c;已知 我们要把两类数据都投影到w直线上。 让不同类别的数据的类别中心之间的距离尽可能的大&#xff0c; 同一种类别数…

线性判别分析LDA原理总结

转自http://www.cnblogs.com/pinard/p/6244265.html 在主成分分析&#xff08;PCA&#xff09;原理总结中&#xff0c;我们对降维算法PCA做了总结。这里我们就对另外一种经典的降维方法线性判别分析&#xff08;Linear Discriminant Analysis, 以下简称LDA&#xff09;做一个总…

线性判别分析(Linear Discriminant Analysis, LDA)算法分析

LDA算法入门 一. LDA算法概述: 线性判别式分析(Linear Discriminant Analysis, LDA),也叫做Fisher线性判别(Fisher Linear Discriminant ,FLD),是模式识别的经典算法,它是在1996年由Belhumeur引入模式识别和人工智能领域的。性鉴别分析的基本思想是将高维的模式样本投影到…

机器学习笔记17-LDA算法

1. LDA算法简介 LDA&#xff08;线性判别式分析 Linear Discriminant Analysis&#xff09;属于机器学习中的监督学习算法&#xff0c;常用来做特征提取、数据降维和任务分类。在人脸识别、人脸检测等领域发挥重要作用。LDA算法与PCA算法都是常用的降维技术。二者的区别在于&a…

数据结构层次遍历二叉树

2022.11.19 计算二叉树的深度和节点个数 任务描述相关知识编程要求测试说明C/C代码 任务描述 本关任务&#xff1a;给定一棵二叉树&#xff0c;借助队列实现层次遍历二叉树。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.队列基本操作&#xff0c;2.二叉…