数据结构:各种结构函数参数辨析

news2024/9/20 1:01:29

(一)顺序表

1)结构

typedef int SLDateType;

typedef struct SeqList
{
	SLDateType* data;
	int size;
	int capacity;
}SeqList;

SeqList ps = { 0 };

2)函数参数

// 对数据的管理:增删查改 
void SeqListInit(SeqList* ps);
void SeqListDestroy(SeqList* ps);

void SeqListPrint(SeqList* ps);
void SeqListPushBack(SeqList* ps, SLDateType x);
void SeqListPushFront(SeqList* ps, SLDateType x);
void SeqListPopFront(SeqList* ps);
void SeqListPopBack(SeqList* ps);

// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos); 

3)分析

这里我们要实现函数的参数怎么设置,其实是根据我们实际需求来设计的。

我们的需求是:

创建一个结构体SeqList ps ,然后通过结构体 ps 访问 data, 在通过 data指针可以找到我们 malloc 空间的起始地址,我们可以通过这个起始地址控制 malloc 的整块空间,以使我们可以在这块空间上进行增删查改等操作。

当我们创建结构体SeqList ps 时,实际上是在内存栈区开辟了一块空间,这块空间存储着三个变量:*data、size、capacity;又因为data是一个指针变量,它又指向一块malloc在堆区开辟的空间,我们所有的数据都将在这块空间上处理。

如果函数传参,传的不是结构体SeqList ps 的地址的话,而是直接将结构体传给函数,这样就会出错,因为这就是典型的传值调用,此时,函数用的参数只是原变量的临时拷贝。

这样我们改变 ps1 ,但 ps 的内容没有改变。要使函数使用的空间和ps相同,就将ps的地址传过去就行了。

所以,函数的参数要传结构体的地址

(二)单向链表:

1)结构

SListNode* phead = NULL;

typedef int SLTDateType;

typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

2)函数参数

由于实现链表可以用两种结构:带哨兵位头节点和不带哨兵位头节点的两种结构,所以函数的参数类型也会有差异,具体类型详见下列分析。

3)分析

  • 将结构体 SListNode1 的地址作为参数(带哨兵位的头节点、一级指针接收)

 与上述顺序表相同的道理,我们可以将结构体 SListNode1 的地址作为参数,但是这样就要求SListNode1 必须要在调用函数前创建,其实这样就是将第一个节点作为哨兵位节点,这个节点不存储数据,只是用来作为链表开头的标记。

在链表中,哨兵节点(也称为虚拟节点或标志节点)是一个特殊的节点,通常不存储实际的数据,而是用于简化链表的操作。哨兵节点位于链表的起始或末尾,它不存储有效的数据,但可以帮助在某些情况下简化代码逻辑。

因此我们的代码如下:

void SListPushBack(SListNode* plist, SLTDateType x)
{
	// 创建新的节点
	SListNode* NewNode = (SListNode*)malloc(sizeof(SListNode));
	NewNode->data = x;
	NewNode->next = NULL;
	// 找到尾节点
	SListNode* current = plist;
	while (current->next != NULL)
	{
		current = current->next;
	}
	current->next = NewNode;
}

int main()
{
	SListNode node1;
	SListPushBack(&node1, 1);
	SListPushBack(&node1, 2);
	SListPushBack(&node1, 3);
	return 0;
}

 

 图解:

小结:

使用带哨兵位的头节点时,函数接收节点的类型为:SListNode*

  •  用一个指针指向头节点(二级指针接收)

 定义一个指针phead ,该指针指向NULL

 由图中可以看出:head指向NULL,所以显示其内部的变量data、next显示“无法读取内存”;

因为我们想要phead指向头节点,而节点又是 SListNode 类型的,所以phead就需要是 SListNode*类型;

在第一次创建节点时,将phead的指向NULL变为指向头节点,这样就改变了phead:

既然改变了phead,就需要传递phead的地址,想要函数接收phead的地址,就要phead变量类型的指针,phead的变量类型是 SListNode*,所以这个指针就需要是SListNode** 类型的。

 

此时phead就不再指向NULL了,而是指向第一个节点(其内部存储的是第一个节点的地址)

通过pplist的解引用就可以找到phead,再通过phead的解引用就可以找到节点的数据域和指针域,进而我们就可以改变节点的数据域,使节点能够存储数据;也可以改变节点的指针域,使各个节点能够连接起来

 小结:

不使用使用带哨兵位的头节点,使用指针指向头节点时,函数接收节点的类型为:SListNode**

当然,并不是所有 “用一个指针指向头节点” 的情形都需要使用二级指针来接收,还可以用函数的返回进行传递。

  • 利用函数返回值(一级指针接收)

这个结构和上面 “用一个指针指向头节点” 结构和原理是一样的,两者的主要差异就在于这次我们利用了初始化函数的返回值。

先来看一下初始化函数是怎样实现的:

ListNode* ListInit(ListNode* plist)
{
	plist = (ListNode*)malloc(sizeof(ListNode));
	plist->next = NULL;
	return plist;
}

ListNode* head = NULL;
head = ListInit(head);

 图解:

第一步:

 

第二步:

 

 此时 head 就已经指向链表的头节点了,通过head的解引用就可以找到节点的数据域和指针域,进而我们就可以改变节点的数据域,使节点能够存储数据;也可以改变节点的指针域,使各个节点能够连接起来。

我们会发现这种方法根上面 “用一个指针指向头节点” 是一模一样的,其实上面一种方法在改变phead的指向后,其他函数的参数就可以可以是phead了,但是必须要在调用插入函数后,才能这样做。当我们先调用其他函数时,就会出错了,所以为了保险起见,我们统一将二级指针作为函数 的参数。

(三)栈

实现栈可以用数组也可以使用链表,而数组的结构对应的是顺序表的结构,所以对于栈的结构这里我就不在赘述了。

	Stack stack;
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top; // 栈顶
	int capacity; // 容量
}Stack;

// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);

(四)队列

这里利用链表实现队列是比较好的,所以队列的结构对应的是链表的结构。需要注意的是,为了便于尾插和获得队列的末尾元素,我们不仅定义了指向头节点的指针,还定义了指向尾节点的指针,对于这两个指针我们又定义了一个结构体。

Queue q;

typedef int QDataType;
 //链式结构:表示队列
typedef struct QListNode
{
	struct QListNode* next;
	QDataType data;
}QNode;

// 队列的结构
typedef struct Queue
{
 QNode* head;
 QNode* tail;
}Queue;

图解:

 


本次内容到此结束了!如果你觉得这篇博客对你有帮助的话 ,希望你能够给我点个赞,鼓励一下我。感谢感谢……

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌推出AI模型机器人RT2 将文本和图像输出为机器人动作

去年年底,ChatGPT火遍全球,全世界都见识了大语言模型的强大力量。人们对大模型不再陌生,开始使用基于大模型的应用绘画、作图、搜索资料、设计剧情等,而妙用不止于此。谷歌推出了Robotics Transformer 2(RT2),这是一个…

2023牛客暑期多校训练营6-C-idol!!

奇数的双阶乘等于小于等于本身的奇数的乘积,偶数的双阶乘等于小于等于本身的非零偶数的乘积。 思路:考虑末位0的个数,我们能想到的最小两数相乘有零的就是2*5,所以本题我们思路就是去找因子2的个数以及因子5的个数,2的…

VR全景乡村旅游浇灭乡愁,近距离体验自然之美

说起乡愁,可能每位漂泊的游子都有所感受,在外漂泊数十载,每到佳节倍思亲,家乡的一草一木都浮现在脑海中,满载着儿时的回忆。为了留住那抹儿时回忆,VR全景助力数字化乡村建设。 乡村振兴是国家的重大战略&am…

flutter开发实战-just_audio实现播放音频暂停音频设置音量等

flutter开发实战-just_audio实现播放音频暂停音频设置音量等 最近开发过程中遇到需要播放背景音等音频播放,这里使用just_audio来实现播放音频暂停音频设置音量等 一、引入just_audio 在pubspec.yaml引入just_audio just_audio: ^2.7.0在iOS上,video_p…

华为OD机试真题 Java 实现【欢快的周末】【2023 B卷 100分】,深度优先搜索dfs算法

目录 专栏导读一、题目描述二、输入描述三、输出描述四、深度优先搜索dfs五、解题思路六、Java算法源码七、效果展示1、输入2、输出3、说明4、如果修改一下呢?5、来,TFBOYS,试一下? 华为OD机试 2023B卷题库疯狂收录中,…

Ubuntu类IOS主题设置

1.依次执行下面三条命令&#xff1a; sudo apt install gnome-shell-extensions sudo apt install gnome-tweak-tool sudo apt install chrome-gnome-shell2.下载主题&#xff0c;也是命令&#xff1a; git clone <https://github.com/qingchendelaike/GNOME-OSX-II-Theme…

VGGNet剪枝实战:使用VGGNet训练、稀疏训练、剪枝、微调等,剪枝出只有3M的模型(二)

文章目录 稀疏训练VGGNet剪枝导入库文件测试函数定义全局参数BN通道排序制作Mask剪枝操作 微调微调方法微调结果 稀疏训练VGGNet 新建train_sp.py脚本。稀疏化训练的过程和正常训练类似&#xff0c;不同的是在BN层中各权重加入稀疏因子&#xff0c;代码如下&#xff1a; def …

通达OA前台getshell

你永远要记住&#xff0c;你跟别人不一样&#xff0c;你是一个有另外世界的人 漏洞复现 访问网站url&#xff1a; 将exp中的target替换为目标url Payload替换为自己的木马即可 ​关键exp如下&#xff1a; 执行exp漏洞利用&#xff0c;中间过程会询问是否删除文件&#x…

Mysql load data隐藏字符特殊字符ESC的方法

mysqlimport --userroot --passwordroot1234 --default-character-setutf8 --fields-terminated-by"$(echo -ne \033)" --lines-terminated-by\n --local shenl /root/xab.dat https://jisuan5.com/ascii/ ascii码值 SHOW GLOBAL VARIABLES LIKE local_infile; LO…

微服务Ribbon-负载均衡原理

目录 一、LoadBalancerIntercepor 二、LoadBalancerClient 三、负载均衡策略IRule 四、总结 上一篇中&#xff0c;我们添加了LoadBalanced注解&#xff0c;即可实现负载均衡功能&#xff0c;这是什么原理呢&#xff1f; SpringCloud底层其实是利用了一个名为Ribbon的组件&…

SpringBoot学习——springboot整合email springboot整合阿里云短信服务

目录 引出springboot整合email配置邮箱导入依赖application.yml配置email业务类测试类 springboot整合阿里云短信服务申请阿里云短信服务测试短信服务获取阿里云的accessKeyspringboot整合阿里云短信导包工具类 总结 引出 1.springboot整合email&#xff0c;qq邮箱&#xff0c;…

计算机网络实验3:双绞线跳线的制作和测试

文章目录 1. 主要教学内容2. 双绞线跳线的制作和测试 1. 主要教学内容 实验内容&#xff1a;掌握双绞线制作过程中的剥线、理线、插线、压线以及测线。所需学时&#xff1a;2。重难点&#xff1a;双绞线的类别及其用途周次&#xff1a;第2周。教材相关章节&#xff1a;第5章&a…

Android Studio实现Spinner下拉列表

效果图 点击下拉列表 点击某一个下拉列表 MainActivity package com.example.spinneradapterpro;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.Spinn…

怎样的公司称为集团?

集团是什么&#xff1f; 集团的意思是有目的组织起来共同行动的团体。企业集团不具有独立的法人资格。《公司法》中并没有“集团”一说。只有有限责任公司和股份有限公司的提法。有的公司进行多元化经营战略&#xff0c;在多个领域均成立了相应的子公司&#xff0c;这样&#…

【递归算法实践】验证二叉搜索树

目录 1. 递归算法 2. 递归实现验证二叉搜索树 3. 递归解法的实现逻辑 4. 递归实现的实例分析 1. 递归算法 递归是一种通过函数自身调用来解决问题的算法&#xff0c;它可以使代码更加简洁和优雅&#xff0c;同时也能够解决许多复杂的问题。在递归中&#xff0c;函数会不断…

【Windows10下启动RocketMQ报错:找不到或无法加载主类 Files\Java\jdk1.8.0_301\lib\dt.jar】解决方法

Windows10下启动RocketMQ报错&#xff1a;找不到或无法加载主类 一、问题产生二、产生原因三、解决办法 一、问题产生 参考RocketMQ Github官网上的说明&#xff0c;下载rocketmq-all-5.1.3-bin-release.zip&#xff0c;解压配置环境变量后&#xff0c;执行如下命令&#xff1a…

基于2.4G RF开发的无线游戏手柄解决方案

平时喜欢玩游戏的朋友&#xff0c;肯定知道键鼠在某些类型的游戏适配和操作方面&#xff0c;不如手柄。作为一个游戏爱好者&#xff0c;还得配上一个游戏手柄才行。比如动作和格斗、体育游戏&#xff0c;由于手柄更合理的摇杆位置和按键布局&#xff0c;操作起来也是得心应手。…

6.pip简介,第三方库的安装

引言 使用过Visual Studio的小伙伴可能对npm不陌生&#xff0c;没错&#xff0c;pip与npm的功能是一样的。 首先要知道&#xff0c;Python这门语言拥有着丰富的标准库以及先辈们开发的各种功能强大的第三方库。而今天我们主要学习的呢就是关于Python中的包管理工具。它是Pytho…

图像的镜像变换之c++实现(qt + 不调包)

1.基本原理 1.水平镜像变化 设图像的宽度为width&#xff0c;则水平镜像变化的映射关系如下&#xff1a; 2.垂直镜像变化 设图像的宽度为height&#xff0c;则垂直镜像变化的映射关系如下&#xff1a; 2.代码实现&#xff08;代码是我以前自学图像处理时写的&#xff0c;代码很…