如何正确方便的理解双指针?力扣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 (二叉树的层序遍历)
双指针,顾名思义就是指针的指针。 在此之前我们需要先理解单指针 (简称为指针)。指针很简单,直接上例子:例:现有两个变量,a10,b20. 要求:交换他们的值,输出的结果应为a20…...

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

力扣:LCR 122. 路径加密 题目:剑指Offer 05.替换空格(c++)
本文章代码以c为例! 力扣:LCR 122. 路径加密 题目: 代码: class Solution { public:string pathEncryption(string path) {for(int i0;i<path.size();i){if(path[i].){path[i] ;}}return path;} }; 难度升级(原…...

cJson堆内存释放问题
cJSON_Delete(),是用来释放json对象的,释放父JSON对象后,子JSON对象也会被释放。 CJSON_free(),是用来释放其他对象的。 int main(void) {cJSON* cjson_test NULL;cJSON* cjson_address NULL;cJSON* cjson_skill NULL;char* s…...

论文阅读/写作扫盲
第一节:期刊科普 JCR分区和中科院分区是用于对期刊进行分类和评估的两种常见方法。它们的存在是为了帮助学术界和研究人员更好地了解期刊的学术质量、影响力和地位。 JCR分区(Journal Citation Reports):JCR分区是由Clarivate Ana…...

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

Android组件通信——ActivityGroup(二十五)
1. ActivityGroup 1.1 知识点 (1)了解ActivityGroup的作用; (2)使用ActivityGroup进行复杂标签菜单的实现; (3)使用PopupWindow组件实现弹出菜单组件开发; 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信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章,请访问专栏: 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.注意事项 二.按键消抖 2.1 LED_deboun…...

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

Vue3路由引入报错解决:无法找到模块“xxx.vue”的声明文件 xxx隐式拥有 “any“ 类型。
这类情况应该遇见过吧,这是因为 TypeScript只能理解 .ts 文件,无法理解 .vue 文件。 解决方法:在项目的根目录或者src文件夹下创建一个后辍为 文件名.d.ts 的文件,并写入一下内容: declare module *.vue {import { …...

基于若依ruoyi-nbcio支持flowable流程分类里增加流程应用类型
更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 主要考虑到流程分很多种,普通的是OA流程,还有自定义业务流程,钉钉流程等…...

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

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

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

linux常用指令
基础命令 cd:用于切换目录。例如,要从当前目录切换到/home/user目录,可以使用命令“cd /home/user”。ls:用于列出目录内容。例如,要列出当前目录的内容,可以使用命令“ls”。mkdir:用于创建目…...

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

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

数据结构--单链表操作
1.单链表的创建(带头结点) #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…...

AlmaLinux (兼容centos)安装Geant4与ROOT
AlmaLinux 介绍 AlmaLinux OS 是一个开源、社区驱动的 Linux 操作系统,它填补了因 CentOS 稳定版本停止维护而留下的空白,同时更加强大。 安装 AlmaLinux 这个我用的是 windows 子系统进行安装 首先打开微软商店,然后搜索AlmaLinux&#…...

FPGA面试题(2)
一.同步复位和异步复位 同步复位:当clk有效时,复位才有效。优点:有利于时序分析,防止毛刺现象出现。缺点:复位信号必须大于时钟周期,大部分逻辑器件中D触发器都只有异步复位端口,需要在寄存器数…...

【C++ Primer Plus学习记录】指针——使用new来创建动态数组
目录 1.使用new创建动态数组 2.使用动态数组(如何使用指针访问数组元素) 如果程序只需要一个值,则可能会声明一个简单变量,因为对于管理一个小型数据对象来说,这样做比使用new和指针更简单。通常,对于大型…...

移动app广告变现,对接广告联盟还是选择第三方聚合广告平台?
作为互联网广告的载体,APP天生就比线下传统广告位更具优势,不受地域限制可以辐射到地球上的每一个角落,可以让广告获得更广的覆盖面。通过丰富的广告形式,精准的目标用户画像,也可以更好地实现品牌广告或效果广告的投放…...

ARM 按键控制 LED灯,蜂鸣器,风扇
main.c: #include "uart.h" #include "key_it.h" int main() {all_led_init();uart4_init();//串口初始化//中断初始化key_it_config();key3_it_config();buzzer_init();fan_init();while(1){//保证主程序不结束}return 0; }src/key_it.c: #include"…...

VirtualBox Ubuntu扩展虚拟机磁盘空间
关于Orical VM VirtualBox虚拟机安装了ubuntu linux系统,由于需要,磁盘空间不足,需要扩展磁盘空间,最终找到了一个非常简单的方法,上干货。 1、关闭虚拟机 2、运用VBoxManage命令扩展vdi文件的空间 打开windows的命…...

C#开发的OpenRA游戏之电力系统之二
C#开发的OpenRA游戏之电力系统之二 继续前面的电力系统分析,在OpenRA游戏里,每一个建筑物都会有一个电力描述字段,说明这个建筑物是消耗电力,还是产生电力的。如果这个建筑物是产生电力的,那么这个字段就会是正值,如果这个建筑物是消耗电力的,就会是负值。因此所有电厂…...

Java架构师基础框架设计
目录 1 导学2 理解软件框架3 框架设计里面的框架和设计模式的关系4 基础框架中常见的基本功能4.1 事务处理4.2 微服务网络调用4.3 缓存实现4.4 分布式id4.5 任务调度4.6 工作流5 基础框架的几种基本的使用方式5.1 继承方式5.2 注解或注解加AOP的方式5.3 将基础框架的功能直接当…...

tortoise创建本地仓库
1.安装git和tortoise 推荐 TortoiseGit的安装与配置方法 以及 Git TortoiseGit 配置步骤以及本地版本管理 这里记录一下我遇到的问题 1.右键没有创建本地版本库 2 .创建了但是克隆不了 后续专有 一般选专有网络 注意自行谨慎选择 自行负责...

【FreeRTOS】【STM32】03 FreeRTOSConfig.h头文件简介与修改
基于[野火]《FreeRTOS%20内核实现与应用开发实战—基于STM32》.pdf FreeRTOSConfig.h头文件是FreeRTOS各项功能的打开与关闭 FreeRTOSConfig.h头文件简介 之前也说过了,FreeRTOSConfig.h文件可以添加在工程中任意文件夹,只需要在路径中添加好了就行。…...