代码随想录算法训练营day13 | 递归遍历、迭代遍历、统一迭代、层序遍历

news/2025/2/26 0:20:40/文章来源:https://www.cnblogs.com/coderjxj/p/18734703

二叉树节点定义

点击查看代码
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/

递归遍历
144. 二叉树的前序遍历(递归)

点击查看代码
class Solution {
public:void Traversal(TreeNode* root, vector<int> &v) {if(root == nullptr) return;v.push_back(root->val);  //根Traversal(root->left, v);  //左Traversal(root->right, v);  //右}vector<int> preorderTraversal(TreeNode* root) {vector<int> result;Traversal(root, result);return result;}
};

94.二叉树的中序遍历(递归)

点击查看代码
class Solution {
public:void Traversal(TreeNode* root, vector<int> &v) {if(root == nullptr) return;Traversal(root->left, v);  //左v.push_back(root->val);  //根Traversal(root->right, v);  //右}vector<int> inorderTraversal(TreeNode* root) {vector<int> result;Traversal(root, result);return result;}
};

145.二叉树的后序遍历(递归)

点击查看代码
class Solution {
public:void Traversal(TreeNode* root, vector<int> &v) {if(root == nullptr) return;Traversal(root->left, v);  //左Traversal(root->right, v);  //右v.push_back(root->val);  //根}vector<int> postorderTraversal(TreeNode* root) {vector<int> result;Traversal(root, result);return result;}
};

迭代遍历
144.二叉树的前序遍历(迭代)

点击查看代码
class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {vector<int> result;if(root == nullptr) return result;//注意栈里存放的是节点的指针stack<TreeNode*> stk;stk.push(root);while(!stk.empty()) {TreeNode *rootEle = stk.top();stk.pop();result.push_back(rootEle->val);  //根//注意是右孩子先入栈,因为先入栈的后处理if(rootEle->right) //注意,迭代写法访问左右时要写if判断,因为不会通过递归终止判断,空指针不入栈stk.push(rootEle->right);  //左if(rootEle->left)stk.push(rootEle->left);  //右}return result;}
};

145.二叉树的后序遍历(迭代)

点击查看代码
class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {vector<int> result;if(root == nullptr) return result;//注意栈里存放的是节点的指针stack<TreeNode*> stk;stk.push(root);while(!stk.empty()) {TreeNode *rootEle = stk.top();stk.pop();result.push_back(rootEle->val);if(rootEle->left) //注意,迭代写法访问左右时要写if判断,因为不会通过递归终止判断,空指针不入栈stk.push(rootEle->left);if(rootEle->right)stk.push(rootEle->right);}reverse(result.begin(), result.end());return result;}
};

迭代法的后序遍历由迭代法的先序遍历稍微修改即可
因为先序是根左右,将其改为根右左,最后再将result数组reverse就成为左右根,刚好为后序
根右左,右先处理,故后入栈,先入栈左孩子

94.二叉树的中序遍历(迭代)
中序遍历的迭代法比较特殊,先跳过...

统一迭代
掌握前序和后序的迭代法即可,中序迭代比较特殊,先跳过,统一迭代先跳过...

层序遍历
层序遍历处理每个节点时,需要将其pop出队列后将其所有孩子都push进队列,才算处理完成
以下所有题目均使用102题层序遍历模板稍作修改即可
102.二叉树的层序遍历

点击查看代码
<details>
<summary>点击查看代码</summary>

class Solution {
public:
vector<vector> levelOrder(TreeNode* root) {
vector<vector> result;
if(root == nullptr) return result;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size(); //核心语句,记录每层的节点个数
vector curResult;
while(size-- > 0) {
TreeNode *cur = que.front();
que.pop();
curResult.push_back(cur->val);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
result.push_back(curResult);
}
return result;
}
};

</details>
本题有一个关键点在于,如何记住每一层的节点个数,使节点为一层一层地push入二维数组中,即将一整层节点作为一个数组push进result数组中

107.二叉树的层序遍历Ⅱ

点击查看代码
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<vector<int>> levelOrderBottom(TreeNode* root) {vector<vector<int>> result;if(root == nullptr) return result;queue<TreeNode*> que;que.push(root);while(!que.empty()) {int size = que.size(); //核心语句,记录每层的节点个数vector<int> curResult;while(size-- > 0) {TreeNode *cur = que.front();que.pop();curResult.push_back(cur->val);if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}result.push_back(curResult);}reverse(result.begin(), result.end()); //正常从上至下层序遍历,最后reverse一下result数组即可得到从下至上层序遍历的结果return result;        }
};

199.二叉树的右视图

点击查看代码
class Solution {
public:vector<int> rightSideView(TreeNode* root) {vector<int> result;if(root == nullptr) return result;queue<TreeNode*> que;que.push(root);while(!que.empty()) {int size = que.size(); //核心语句,记录每层的节点个数bool flag = 1; //flag为1表示为当前行最右边的元素while(size-- > 0) {TreeNode *cur = que.front();que.pop();if(flag == 1) {result.push_back(cur->val);flag = 0; //关闭,当前行的后续元素不再push进结果数组}if(cur->right) que.push(cur->right);if(cur->left) que.push(cur->left);}}return result;}
};

本题关键点在于采用flag标志来表示当前元素是否为当前行的最右边的元素

637.二叉树的层平均值

点击查看代码
class Solution {
public:vector<double> averageOfLevels(TreeNode* root) {vector<double> result;if(root == nullptr) return result;queue<TreeNode*> que;que.push(root);while(!que.empty()) {int size = que.size(); //核心语句,记录每层的节点个数int len = size; //用于最后的除法求平均double sum = 0; //特别注意sum值需要为double型,因为结果数组为vector<double>while(size-- > 0) {TreeNode *cur = que.front();que.pop();sum += cur->val;if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}result.push_back(sum / len);}return result;}
};

429.N叉树的层序遍历
注意本题的节点定义,由于有多个孩子,故不使用左右指针,而使用指针数组表示孩子

点击查看代码
class Solution {
public:vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> result;if(root == nullptr) return result;queue<Node*> que;que.push(root);while(!que.empty()) {int size = que.size(); //核心语句,记录每层的节点个数vector<int> curResult;while(size-- > 0) {Node *cur = que.front();que.pop();curResult.push_back(cur->val);for(int i = 0; i < cur->children.size(); ++i) que.push(cur->children[i]);}result.push_back(curResult);}return result;}
};

515.在每个树行中找最大值

点击查看代码
class Solution {
public:vector<int> largestValues(TreeNode* root) {vector<int> result;if(root == nullptr) return result;queue<TreeNode*> que;que.push(root);while(!que.empty()) {int size = que.size(); //核心语句,记录每层的节点个数int maxNum = INT_MIN;  //INT_MIN INT_MAX常量位于<climits>中while(size-- > 0) {TreeNode *cur = que.front();que.pop();maxNum = max(maxNum, cur->val);if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}result.push_back(maxNum);}return result;}
};

116.填充每个节点的下一个右侧节点指针

点击查看代码
class Solution {
public:Node* connect(Node* root) {if(root == nullptr) return root;queue<Node*> que;que.push(root);while(!que.empty()) {int size = que.size(); //核心语句,记录每层的节点个数Node *pre = nullptr;while(size-- > 0) {Node *cur = que.front();que.pop();//处理每个节点的逻辑是让前一个节点指向当前节点,而不处理当前节点的next指针if(pre != nullptr) {  //若不是当前行第一个元素,则令前一个元素指向当前元素,并更新pre指针pre->next = cur;pre = cur;}else {pre = cur;  //若是当前行第一个元素,则令pre指向当前元素}if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}//由于初始状态下,所有next指针均为nullptr,故每行最后一个元素无需再处理}return root;        }
};

117.填充每个节点的下一个右侧节点指针II
完全同116,和是不是满二叉树没有半毛钱关系

点击查看代码
class Solution {
public:Node* connect(Node* root) {if(root == nullptr) return root;queue<Node*> que;que.push(root);while(!que.empty()) {int size = que.size(); //核心语句,记录每层的节点个数Node *pre = nullptr;while(size-- > 0) {Node *cur = que.front();que.pop();//处理每个节点的逻辑是让前一个节点指向当前节点,而不处理当前节点的next指针if(pre != nullptr) {  //若不是当前行第一个元素,则令前一个元素指向当前元素,并更新pre指针pre->next = cur;pre = cur;}else {pre = cur;  //若是当前行第一个元素,则令pre指向当前元素}if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}//由于初始状态下,所有next指针均为nullptr,故每行最后一个元素无需再处理}return root; }
};

104.二叉树的最大深度(层序遍历)

点击查看代码
class Solution {
public:int maxDepth(TreeNode* root) {int depth = 0;if(root == nullptr) return depth;queue<TreeNode*> que;que.push(root);while(!que.empty()) {++depth; //处理新的一层int size = que.size(); //核心语句,记录每层的节点个数while(size-- > 0) {TreeNode *cur = que.front();que.pop();if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return depth;}
};

111.二叉树的最小深度(层序遍历)
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
核心是要使用层序遍历找到第一个叶子节点,找到后直接返回其所在层数

点击查看代码
class Solution {
public:int minDepth(TreeNode* root) {int depth = 0;if(root == nullptr) return depth;queue<TreeNode*> que;que.push(root);while(!que.empty()) {++depth; //处理新的一层int size = que.size(); //核心语句,记录每层的节点个数while(size-- > 0) {TreeNode *cur = que.front();que.pop();//核心就是找第一个叶节点,找到后直接返回其深度,同时,求最小深度题仅比求最大深度题多了以下一行代码if(cur->left == nullptr && cur->right == nullptr) return depth;if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);}}return depth;}
};

2025/02/26

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

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

相关文章

再论支付账务

支付账务是金融领域中复杂且关键的一环,涉及资金流动、风险控制和业务效率等多个方面。本文从支付结算的专业视角出发,深入剖析了支付账务的核心逻辑,包括会计科目设置、对账结算流程以及账务核算的关键要点。学习账务的时候你是否经常有这些疑问“待结算和待清算是什么?为…

分享[清华大学DeepSeek教程全家桶]下载地址

干货分享,最新整理的清华大学DeepSeek教程全家桶,内容如下:内容展示下载地址🎁🎁 文末福利,后台回复[603]获取下载地址 📢📢 喜欢这篇文章?欢迎大家✨关注 ❤️点赞 ➡️转发 分享给那些需要的朋友!如果认为此文对您有帮助,别忘了支持一下哦!声明:本博客原创文…

求二叉搜索树的第 K 小的值

题目:一个二叉搜索树,求其中的第K小的节点值。如下图,第3小的节点是4什么是二叉树:是一棵树   每个节点最多能有 2 个字节点。数据结构如下:{value, left,right}interface ITreeNode {value: number // 或其它类型left?: ITreeNoderight?:ITreeNode }上图中的二叉树结…

百万架构师第四十四课:Nginx:Nginx 的扩展-OpenRestry|JavaGuide

百万架构师系列文章阅读体验感更佳 原文链接:https://javaguide.net 公众号:不止极客 Nginx 的扩展-OpenRestry 课程目标Nginx 进程模型简介Nginx 的高可用方案OpenResty 安装及使用什么是 API 网关?OpenResty 实现灰度发布功能Nginx 进程模型简介 多进程TomcatBIO NIO AION…

不用 ORM 会发生什么?

要弄清一个事物带来了什么,有种办法就是在场景中去掉它,当我们不使用 ORM 开发项目,需要补齐哪些能力,以表格形式列举要补齐的功能点和意义。我们仅能通过 SQL语句和数据库交互,在采用 ORM 项目开发的项目有时出于性能、数据库表达限制的原因而直接编写 SQL 语句,在脱离 …

事务中无法切换数据源?DataSourceSwitchInvoker:轻松实现多数据源切换执行工具类

背景: 在有标注为@Transactional的类或公共方法中(传播特性,如:NOT_SUPPORTED、SUPPORTS、REQUIRED【默认值】、REQUIRES_NEW)执行数据源切换可能不成功(比如:主从数据源切换,多数据源切换等,均会发现切换不成功,或“偶尔又切换成功”),导致本应该需要查主库却查了…

Java基础05(常用类)

匿名内部类 Object类 包装类 String类 BigDecimal类 Date类(特定时间)Calendar类(日历)SimpleDateFormat类(格式化时间)System类(系统类)Java基础05(常用类) 内部类 成员内部类在类的内部定义,与实例变量、实例方法同级别的类外部类的一个实例部分,创建内部类对象…

mysql表字段varchar(10)和varchar(255)测试文件占用

前言全局说明一、说明 1.1 环境: Windows 11 家庭版 23H2 22631.3737 MySQL: 服务器版本: 5.6.34 - MySQL Community Server (GPL) Navicat for MySQL: 10.1.71.2 测试样本 两个字段: id字段是 1~10位不等长度的随机数; num字段是 11~25位不等的随机数字;为了更好模拟实际使…

FreeRTOS高效应用实战

FreeRTOS高效应用实战 基于STM32CubeIDE生成对芯片移植好的FreeRTOS工程,使用HAL库编写FreeRTOS应用程序,实现FreeRTOS高效应用实战引入函数句柄的概念函数句柄(Function Handle)是编程中用于间接引用和操作函数的一种机制,其本质是将函数作为数据来传递和存储。以下是关于…

解决ZYNQ-7020开发板使用vitis编译uboot报错和无法正常调试的问题

整个学习过程是参考正点原子启明星开发板的2020.2版本嵌入式Linux开发指南,在学习uboot移植的时候遇到了问题。 新建工程和配置环境啥的和教程里都一样,就不罗嗦了,这里重点讲和教程不一样的地方(或者说教程里有问题的地方)。 新建工程后编译时遇到的报错 在按照教程新建ub…

markDown学习日记

标题 标题是通过#和一个空格来创建,标题的等级是通过#的个数来鉴别。 字体样式 进步进步进步 加粗效果由2个*前后包裹来实现 进步进步进步 斜体需要一个*来实现 (两者都实现需要三个*) 进步进步进步 删除需要两边都用波浪号 ~ 实现 引用明德新民 止于至善用>实…