当前位置: 首页 > news >正文

如何正确方便的理解双指针?力扣102 (二叉树的层序遍历)

双指针,顾名思义就是指针的指针。
在此之前我们需要先理解单指针 (简称为指针)。指针很简单,直接上例子:例:现有两个变量,a=10,b=20.
要求:交换他们的值,输出的结果应为a=20,b=10。

#include <bits/stdc++.h>
using namespace std;void swap(int a, int b) {int temp = a;a = b;b = temp;
}int main() {int a = 10, b = 20;swap(a, b);cout << a << " " << b << endl;return 0;
}

乍一看没问题,结果:在这里插入图片描述
交换失败。失败的原因是在函数swap(int a,int b)中,接收的a和b是两个整型的值而不是指针(换句话说,这里交换的是形式参数而非实际参数)。int a=10;int b=10;定义的是两个实际参数,swap(int a,int b)中的a和b是形式参数,形参的交换对实参的交换是没有影响的。因此要将void swap(int a, int b)修改为void swap(int &a, int &b)

#include <bits/stdc++.h>
using namespace std;
void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}
int main() {int a = 10;int b = 20;swap(a, b);cout << a << " " << b << endl;return 0;
}

在这里插入图片描述
成功。这里的void swap(int &a, int &b)是引用传递,当你调用这个函数时交换操作会直接修改变量a和b的值。这意味着函数外部的变量a和b的值也会发生交换。
当你使用swap(int *a, int *b)函数时得出的结果和上述的引用传参是一样的,但是原理不同:此时参数a和b是指向整型的指针,函数内部通过指针操作来交换变量的值。

void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}它们的运行结果相同。总结:**引用方式和指针方式**的交换两个变量的值的区别:
1、语法:
引用方式:使用引用作为形式参数,在函数内部直接操作引用所绑定的变量。
指针方式:使用指针作为形式参数,在函数内部通过引用指针所指向的地址来修改变量的值。因此引用方式的执行效率更高。
2、调用方式:
**引用方式直接将变量作为实际参数传递给函数**,无需取地址操作。
**指针方式:将变量的地址作为实际参数传递给函数**,在调用时取地址操作符&。
3、影响范围:
引用方式通过**引用传递,函数内部的修改会直接影响到函数外部的变量**。
指针方式:通过**指针传递,函数内部的修改只影响指针所指向的内存地址**,不会修改指针外部的变量。*注意:在函数内部修改指针指向的值,则会影响函数外部的变量。*
4、错误处理:
**引用方式的引用必须绑定到一个已存在的对象,**所以在使用引用方式交换值时不需要考虑空指针或者野指针的可能性。
**指针方式:指针可以为NULL或者指向未知的内存地址**,所以在使用指针交换值时需要注意指针的有效性,避免空指针或者野指针的访问。# 因此:我们明白了:引用方式更为简洁和安全;指针方式更加灵活,可以处理更多的特殊情况,但是相对复杂。接下来就可以开始介绍:**双指针**```cpp
#include <bits/stdc++.h>
using namespace std;void swap(int **a, int **b) {int *temp = *a;*a = *b;*b = temp;
}int main() {int a = 10;int b = 20;int *str1 = &a;int *str2 = &b;swap(&str1, &str2);cout << *str1 << " " << *str2 << endl;return 0;
}

在这里插入图片描述
和单指针对比着看就很直观了!swap的形式参数的a和b各多了一颗“*”,整型变量temp多了一颗*。其余的没有变化。因此双指针就是给指针又套上了一个指针,并没有很复杂。学完了双指针,我们来做一题对应的习题:LeetCode102 二叉树的层次遍历
在这里插入图片描述
核心代码:

int **levealOrder(struct TreeNode *root, int *returnSize, int **returnColumnSizes) { //层序遍历函数int **ans = (int **)malloc(sizeof(int *) * 2000); //动态创建一个二维数组ans用于存储层序遍历的结果*returnSize = 0; //所在层数if (!root)return NULL;int columnSizes[2000];//存所在层的结点struct TreeNode *queue[2000];//用于存储结点的队列int rear = 0, head = 0; //表示队头和队尾的索引queue[rear++] = root; //将结点进入队列while (rear != head) {ans[(*returnSize)] = (int *)malloc(sizeof(int) * (rear - head)); //存储当前结点columnSizes[(*returnSize)] = rear - head; //存储当前层的结点数量int start = head; //当前层在队列中的起始位置head = rear; //头部索引变为尾部索引,表示将要开始遍历下一层for (int i = start; i < head; i++) { //遍历当前层的所有结点ans[(*returnSize)][i - start] = queue[i]->val;if (queue[i]->left)queue[rear++] = queue[i]->left;if (queue[i]->right)queue[rear++] = queue[i]->right;}(*returnSize)++;}*returnColumnSizes = (int *)malloc(sizeof(int) * (*returnSize));for (int i = 0; i < *returnSize; i++)(*returnColumnSizes)[i] = columnSizes[i];return ans;
}

该算法是一个层序遍历算法.层序遍历的过程用大白话描述就是:
if 无根结点,结束
else 有根结点
(1)先遍历根结点;
(2)若有左孩子,将左结点放入队列数组中;
(3)若有右孩子,将右结点放入队列数组中;
重复上述过程直到结点为NULL。

关于这个算法核心部分的解释:首先levealOrder函数的形式参数有3个,第一个是单指针指向(或者说引用)根结点root,
第二个是单指针指向层序遍历的初始层数,
第三个是双指针指向每层结点数量的数组。
该函数最终要返回一个存储层序遍历结果的二维数组ans[][].

int **ans指向一个动态创建的二维数组,用于存储层序遍历的结果:
行代表所在层,列代表所在层的结点位置。即ans[returnSize][rear-head].
(rear-head)是当前层的结点的位置。head和rear分别是队头和队尾的索引。
queue[]用于存储结点以方便遍历。
columnSize用于存储每层结点的数量;

完整代码:

#include <bits/stdc++.h>
using namespace std;typedef struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
} TreeNode;TreeNode *createNode(int val) {TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode));newNode ->val = val;newNode ->left = NULL;newNode ->right = NULL;return newNode;
}int **levealOrder(struct TreeNode *root, int *returnSize, int **returnColumnSizes) { //层序遍历函数int **ans = (int **)malloc(sizeof(int *) * 2000); //动态创建一个二维数组ans用于存储层序遍历的结果*returnSize = 0; //所在层数if (!root)return NULL;int columnSizes[2000];//存所在层的结点struct TreeNode *queue[2000];//用于存储结点的队列int rear = 0, head = 0; //表示队头和队尾的索引queue[rear++] = root; //将结点进入队列while (rear != head) {ans[(*returnSize)] = (int *)malloc(sizeof(int) * (rear - head)); //存储当前结点columnSizes[(*returnSize)] = rear - head; //存储当前层的结点数量int start = head; //当前层在队列中的起始位置head = rear; //头部索引变为尾部索引,表示将要开始遍历下一层for (int i = start; i < head; i++) { //遍历当前层的所有结点ans[(*returnSize)][i - start] = queue[i]->val;if (queue[i]->left)queue[rear++] = queue[i]->left;if (queue[i]->right)queue[rear++] = queue[i]->right;}(*returnSize)++;}*returnColumnSizes = (int *)malloc(sizeof(int) * (*returnSize));for (int i = 0; i < *returnSize; i++)(*returnColumnSizes)[i] = columnSizes[i];return ans;
}int main() {TreeNode *root = createNode(3);root->left = createNode(9);root->right = createNode(20);root->right->left = createNode(15);root->right->right = createNode(20);int returnSize;//记录当前层数int *returnColumnSizes;//存放当前层结点的数组int **result = levealOrder(root, &returnSize, &returnColumnSizes);for (int i = 0; i < returnSize; i++) {cout << "第" << (i + 1) << "层:";for (int j = 0; j < returnColumnSizes[i]; j++)cout << result[i][j] << " " ;cout << endl;}for (int i = 0; i < returnSize; i++)free(result[i]);//动态创建的空间用完之后要释放掉,避免内存泄漏的风险。free(result);free(returnColumnSizes);return 0;
}

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

相关文章:

如何正确方便的理解双指针?力扣102 (二叉树的层序遍历)

双指针&#xff0c;顾名思义就是指针的指针。 在此之前我们需要先理解单指针 &#xff08;简称为指针&#xff09;。指针很简单&#xff0c;直接上例子&#xff1a;例&#xff1a;现有两个变量&#xff0c;a10,b20. 要求&#xff1a;交换他们的值&#xff0c;输出的结果应为a20…...

Vue或uniapp引入自定义字体

一、为什么引入字体 对于大部分APP或网站而言&#xff0c;字体是很重要的一部分。在前端开发中&#xff0c;选用合适的字体往往会极大地提升网站的视觉体验。然而&#xff0c;网页中默认字体的种类和风格有限&#xff0c;且在不同的设备、浏览器上渲染效果不尽相同。因此&…...

​力扣:LCR 122. 路径加密​ 题目:剑指Offer 05.替换空格(c++)

本文章代码以c为例&#xff01; 力扣&#xff1a;LCR 122. 路径加密 题目&#xff1a; 代码&#xff1a; class Solution { public:string pathEncryption(string path) {for(int i0;i<path.size();i){if(path[i].){path[i] ;}}return path;} }; 难度升级&#xff08;原…...

cJson堆内存释放问题

cJSON_Delete()&#xff0c;是用来释放json对象的&#xff0c;释放父JSON对象后&#xff0c;子JSON对象也会被释放。 CJSON_free()&#xff0c;是用来释放其他对象的。 int main(void) {cJSON* cjson_test NULL;cJSON* cjson_address NULL;cJSON* cjson_skill NULL;char* s…...

论文阅读/写作扫盲

第一节&#xff1a;期刊科普 JCR分区和中科院分区是用于对期刊进行分类和评估的两种常见方法。它们的存在是为了帮助学术界和研究人员更好地了解期刊的学术质量、影响力和地位。 JCR分区&#xff08;Journal Citation Reports&#xff09;&#xff1a;JCR分区是由Clarivate Ana…...

一文拿捏对象内存布局及JMM(JAVA内存模型)

1 JMM(Java Memory Model) 1 概述 Java内存模型(Java Memory Model简称JMM)是一种抽象的概念&#xff0c;并不真实存在&#xff0c;它描述的一组规则或者规范。通过这些规则、规范定义了程序中各个变量的访问方式。jvm运行的程序的实体是线程&#xff0c;而每个线程运行时&am…...

Android组件通信——ActivityGroup(二十五)

1. ActivityGroup 1.1 知识点 &#xff08;1&#xff09;了解ActivityGroup的作用&#xff1b; &#xff08;2&#xff09;使用ActivityGroup进行复杂标签菜单的实现&#xff1b; &#xff08;3&#xff09;使用PopupWindow组件实现弹出菜单组件开发&#xff1b; 1.2 具体…...

js的继承的方式

1.对象冒充继承 使用 bind,call,apply 解决构造函数属性的继承 缺点:不能继承原型上的属性和方法 //-------------父类-------------function Person(name, age, sex) {this.name name;this.age age;this.sex sex;}Person.prototype.run function () {console.log(我${this…...

聊聊HttpClient的重试机制

序 本文主要研究一下HttpClient的重试机制 HttpRequestRetryHandler org/apache/http/client/HttpRequestRetryHandler.java public interface HttpRequestRetryHandler {/*** Determines if a method should be retried after an IOException* occurs during execution.**…...

北邮22级信通院数电:Verilog-FPGA(4)第三周实验:按键消抖、呼吸灯、流水灯 操作流程注意事项

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.注意事项 二.按键消抖 2.1 LED_deboun…...

Ghidra101再入门(上?)-Ghidra架构介绍

Ghidra101再入门(上&#xff1f;)-Ghidra架构介绍 最近有群友问我&#xff0c;说&#xff1a;“用了很多年的IDA&#xff0c;最近想看看Ghidra&#xff0c;这应该怎么进行入门&#xff1f;“这可难到我了。。 我发现&#xff0c;市面上虽然介绍Ghidra怎么用的文章和书籍很多&…...

Vue3路由引入报错解决:无法找到模块“xxx.vue”的声明文件 xxx隐式拥有 “any“ 类型。

这类情况应该遇见过吧&#xff0c;这是因为 TypeScript只能理解 .ts 文件&#xff0c;无法理解 .vue 文件。 解决方法&#xff1a;在项目的根目录或者src文件夹下创建一个后辍为 文件名.d.ts 的文件&#xff0c;并写入一下内容&#xff1a; declare module *.vue {import { …...

基于若依ruoyi-nbcio支持flowable流程分类里增加流程应用类型

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 主要考虑到流程分很多种&#xff0c;普通的是OA流程&#xff0c;还有自定义业务流程&#xff0c;钉钉流程等…...

JS之同步异步promise、async、await

promise异步操作 Promise是异步编程的一种解决方案 JavaScript异步与同步解析 学习promise前我们先来了解下什么是异步&#xff1f; 基本概念&#xff1a; 消息队列中的任务分为宏任务与微任务;调用栈也可以称为主线程 首先我们要知道js是单线程语言&#xff0c;也就是说…...

【OpenCV • c++】自定义直方图 | 灰度直方图均衡 | 彩色直方图均衡

文章目录 一、什么是直方图二、自定义直方图三、灰度直方图均衡四、彩色直方图均衡一、什么是直方图 直方图广泛应用于很多计算机视觉处理当中。通过标记帧与帧之间显著的边缘和颜色的变化,可以检测视频中的场景变化。在每个兴趣点设置一个有相似特征的直方图所构成的“标签”…...

el-tree目录和el-table实现搜索定位高亮方法

需求&#xff1a;el-tree目录实现搜索查询el-table表格项&#xff0c;双击表格项根据yiZhuMLID||muLuID定位el-tree目录&#xff0c;并且高亮展示在可视化区域内&#xff0c;再重新根据el-tree目录的yiZhuMLID搜索刷新el-table表格&#xff0c;定位且高亮展示相对应的yiZhuMLID…...

linux常用指令

基础命令 cd&#xff1a;用于切换目录。例如&#xff0c;要从当前目录切换到/home/user目录&#xff0c;可以使用命令“cd /home/user”。ls&#xff1a;用于列出目录内容。例如&#xff0c;要列出当前目录的内容&#xff0c;可以使用命令“ls”。mkdir&#xff1a;用于创建目…...

C语言,指针的一些运算

若创建一个数组&#xff1a;int arr[10] 0; 用指针变量来储存数组首元素的地址&#xff1a;int* p arr,这里arr是数组名&#xff0c;表示首元素地址。 若p p 1或者p之后p本来指向数组首元素地址&#xff0c;就变成了指向第二个元素的地址&#xff0c;p n即指向第n 1个地…...

iPhone 如何强制重启

参考iPhone的官方使用手册 传送门 尤其当 iPhone 未响应&#xff0c;也无法将其关机再开机&#xff0c;此方法最有效&#xff1a; 按住调高音量按钮&#xff0c;然后快速松开。按住调低音量按钮&#xff0c;然后快速松开。按住侧边按钮。当 Apple 标志出现时&#xff0c;松开侧…...

数据结构--单链表操作

1.单链表的创建&#xff08;带头结点&#xff09; #include<stdlib.h> #define ElemType int typedef struct {//定义一个结点ElemType data;struct STU* next; }STU,*LinkList; bool InitList(LinkList& L) {L (STU*)malloc(sizeof(STU));//创建头结点if (L NUL…...

ESP32-S3驱动JW01二氧化碳传感器:从供电陷阱到数据解析的实战指南

1. 硬件连接&#xff1a;电压匹配是生死线 第一次拿到JW01传感器时&#xff0c;我像往常一样顺手接上了ESP32-S3开发板的5V引脚——毕竟大多数传感器模块都标着"5V供电"的字样。结果串口监视器里一片死寂&#xff0c;连乱码都没有。翻出万用表测量才发现&#xff0c;…...

别再只会用FFT了!用MATLAB的czt函数实现窄带信号高分辨率频谱分析

别再只会用FFT了&#xff01;用MATLAB的czt函数实现窄带信号高分辨率频谱分析 在信号处理领域&#xff0c;频谱分析是最基础也是最重要的技术之一。传统上&#xff0c;工程师们习惯使用快速傅里叶变换&#xff08;FFT&#xff09;来获取信号的频域信息。然而&#xff0c;当面对…...

AlphaFold单元测试:代码质量保证

AlphaFold单元测试&#xff1a;代码质量保证 【免费下载链接】alphafold Open source code for AlphaFold 2. 项目地址: https://gitcode.com/GitHub_Trending/al/alphafold 引言&#xff1a;为什么AlphaFold需要严格的单元测试&#xff1f; AlphaFold作为革命性的蛋白…...

DAMOYOLO-S惊艳效果案例集:多领域高难度场景检测展示

DAMOYOLO-S惊艳效果案例集&#xff1a;多领域高难度场景检测展示 今天咱们不聊枯燥的理论和复杂的部署&#xff0c;直接来看点“硬货”。如果你正在寻找一个能在各种刁钻场景下都表现稳定的目标检测模型&#xff0c;那么DAMOYOLO-S绝对值得你花几分钟了解一下。它不是什么新概…...

Kook Zimage 真实幻想 Turbo在软件测试中的应用:自动化UI设计验证

Kook Zimage 真实幻想 Turbo在软件测试中的应用&#xff1a;自动化UI设计验证 1. 引言&#xff1a;UI设计验证的痛点与机遇 在软件开发流程中&#xff0c;UI设计验证一直是个让人头疼的环节。测试人员需要对照设计稿&#xff0c;逐个像素检查界面元素的位置、颜色、字体和布局…...

Phi-4-mini-reasoning开源大模型教程:免配置镜像+128K长文本推理实战

Phi-4-mini-reasoning开源大模型教程&#xff1a;免配置镜像128K长文本推理实战 1. 模型简介 Phi-4-mini-reasoning是一个轻量级开源大语言模型&#xff0c;专注于高质量推理任务。作为Phi-4模型家族成员&#xff0c;它具备以下核心特点&#xff1a; 推理能力突出&#xff1…...

企业级母婴商城系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

摘要 随着互联网技术的快速发展和电子商务的普及&#xff0c;母婴用品市场呈现出蓬勃发展的态势。年轻父母对于母婴产品的需求日益多样化&#xff0c;传统的线下零售模式已无法满足其便捷、高效、个性化的购物需求。因此&#xff0c;构建一个功能完善、安全可靠的企业级母婴商城…...

SPIRAN ART SUMMONER图像生成前端展示效果优化技巧

SPIRAN ART SUMMONER图像生成前端展示效果优化技巧 1. 引言 你有没有遇到过这种情况&#xff1a;用SPIRAN ART SUMMONER生成了超棒的图片&#xff0c;但在网站上展示时却加载缓慢&#xff0c;用户还没看到效果就流失了&#xff1f;或者图片显示不完整&#xff0c;影响了整体的…...

Git-RSCLIP入门到精通:从基础地物识别到复杂场景分析全流程解析

Git-RSCLIP入门到精通&#xff1a;从基础地物识别到复杂场景分析全流程解析 1. 遥感智能分析的新利器 在遥感图像分析领域&#xff0c;传统方法往往需要大量标注数据和复杂的模型训练流程。Git-RSCLIP的出现彻底改变了这一局面&#xff0c;它基于先进的SigLIP架构&#xff0c…...

从单片机思维到FPGA思维:我用Xilinx Ego1做循迹小车踩过的那些‘坑’

从单片机思维到FPGA思维&#xff1a;Xilinx Ego1循迹小车开发实战避坑指南 第一次用FPGA做循迹小车时&#xff0c;我盯着Vivado里密密麻麻的时序报告发呆了半小时——这和我熟悉的单片机开发完全是两个世界。作为有三年STM32开发经验的工程师&#xff0c;本以为凭借Verilog语法…...