当前位置: 首页 > 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…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...