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

(一)顺序表

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;

图解:

 


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

webpack基础知识六:说说webpack的热更新是如何做到的?原理是什么?

一、是什么 HMR全称 Hot Module Replacement,可以理解为模块热替换,指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个应用 例如,我们在应用运行过程中修改了某个模块,通过自动刷新会导致…

Android Glide MemorySizeCalculator计算值,Kotlin

Android Glide MemorySizeCalculator计算值,Kotlin for (i in 100..1000 step 50) {val calculator MemorySizeCalculator.Builder(this).setMemoryCacheScreens(i.toFloat()).setBitmapPoolScreens(i.toFloat()).setMaxSizeMultiplier(0.8f).setLowMemoryMaxSizeMultiplier(0…

小程序wx:else提示 Bad attr `wx

问题&#xff1a;以下wx:for里的wx:if &#xff0c; wx:else 会报这个错&#xff1a;Bad attr wx <scroll-view class"scroll1" scroll-x enable-flex"true"><view wx:if"{{playlist.length>0}}" class"item" wx:for"…

C++入门--string类的实现

目录 1.string类常用函数实现&#xff08;1&#xff09;string类成员变量定义&#xff08;2&#xff09; string类默认构造函数实现&#xff08;3&#xff09; string类拷贝构造函数实现&#xff08;4&#xff09;string类析构函数&#xff08;5&#xff09;string类c_str()函数…

redis的配置和使用、redis的数据结构以及缓存遇见的常见问题

目录 1.缓存 2.redis不仅仅可以做缓存&#xff0c;只不过说他的大部分场景&#xff0c;是做缓存。本地缓存重启后缓存里的东西就没有了&#xff0c;但是redis有。 3.redis有几个特性:查询快&#xff0c;但是是放到内存里的〈断电或者重启&#xff0c;数据就丢了)&#xff0c…

小研究 - Mysql快速全同步复制技术的设计和应用(三)

Mysql半同步复制技术在高性能的数据管理中被广泛采用&#xff0c;但它在可靠性方面却存在不足.本文对半同步复制技术进行优化&#xff0c;提出了一种快速全同步复制技术&#xff0c;通过对半同步数据复制过程中的事务流程设置、线程资源合理应用、批量日志应用等技术手段&#…

W5100S-EVB-PICO 做TCP Server进行回环测试(六)

前言 上一章我们用W5100S-EVB-PICO开发板做TCP 客户端连接服务器进行数据回环测试&#xff0c;那么本章将用开发板做TCP服务器来进行数据回环测试。 TCP是什么&#xff1f;什么是TCP Server&#xff1f;能干什么&#xff1f; TCP (Transmission Control Protocol) 是一种面向连…

用C语言构建一个数字识别深度神经网络

接上一篇: 用C语言构建一个数字识别卷积神经网络 1. 深度神经网络 按照深度学习的理论&#xff0c;随着神经网络层数的增加&#xff0c;网络拟合复杂问题的能力也会增强&#xff0c;对事物特征的挖掘也会更加深入&#xff0e;这里尝试构建一个&#xff15;层深度的神经网络&am…

【逗老师的PMP学习笔记】9、项目资源管理

目录 一、规划资源管理1、【关键工具】责任分配矩阵RACI矩阵2、【关键工具】组织理论2.1、马斯洛需求层次理论2.2、麦格雷戈-X-Y理论2.3、赫兹伯格双因素理论 3、【关键输出】资源管理计划4、【关键输出】团队章程 二、估算活动资源1、【关键输入】资源日历 三、获取资源1、【关…

LeetCode_01 精度丢失

1281. 整数的各位积和之差 给你一个整数 n&#xff0c;请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。 示例 输入&#xff1a;n 234 输出&#xff1a;15 解释&#xff1a; 各位数之积 2 * 3 * 4 24 各位数之和 2 3 4 9 结果 24 - 9 15示例 …

【计算机视觉】干货分享:Segmentation model PyTorch(快速搭建图像分割网络)

一、前言 如何快速搭建图像分割网络&#xff1f; 要手写把backbone &#xff0c;手写decoder 吗&#xff1f; 介绍一个分割神器&#xff0c;分分钟搭建一个分割网络。 仓库的地址&#xff1a; https://github.com/qubvel/segmentation_models.pytorch该库的主要特点是&#…

【2.2】Java微服务:Hystrix的详解与使用

目录 分布式系统面临问题 Hystrix概念 Hystrix作用 降级 什么是降级 order服务导入Hystrix依赖&#xff08;简单判断原则&#xff1a;谁调用远程谁加&#xff09; 启动类添加注解 业务方法添加注解&#xff08;冒号里填回调方法名&#xff0c;回调方法返回兜底数据&…

沁恒ch32V208处理器开发(二)工程配置

概述 MounRiver Studio在进行任何项目的开发时&#xff0c;为了提高效率&#xff0c;往往需要复用芯片厂家或第三方开发的成熟模块&#xff0c;这些模块通过一个.wvproj文件来进行组织&#xff0c;主要包含&#xff1a; 1&#xff09;MCU厂家提供的硬件接口文件&#xff0c;包…

Windows使用docker desktop 安装kafka、zookeeper集群

docker-compose安装zookeeper集群 参考文章&#xff1a;http://t.csdn.cn/TtTYI https://blog.csdn.net/u010416101/article/details/122803105?spm1001.2014.3001.5501 准备工作&#xff1a; ​ 在开始新建集群之前&#xff0c;新建好文件夹&#xff0c;用来挂载kafka、z…

设计师常用的6款UI设计工具

在选择UI设计工具时&#xff0c;设计师需要关注UI设计工具的功能。市场上有很多设计UI的工具。既然UI设计工具这么多&#xff0c;设计师应该如何选择UI设计工具&#xff1f;本文盘点了6种流行的UI设计工具&#xff0c;快来看看。 1.即时设计 即时设计是一款免费的在线 UI 设计…

Kubernetes kubectl管理命令使用方法

陈述式资源管理方法&#xff08;通过命令行&#xff09; 1.kubernetes 集群管理集群资源的唯一入口是通过相应的方法调用 apiserver 的接口 2.kubectl 是官方的CLI命令行工具&#xff0c;用于与 apiserver 进行通信&#xff0c;将用户在命令行输入的命令&#xff0c;组织并转化…

element-ui表格跨页多选实现

前言 在我们日常项目开发中,经常会有表格跨页多选的需求,接下来让我们用 el-table 示例一步步来实现这个需求。 动手开发 在线体验 https://codesandbox.io/s/priceless-mcclintock-4cp7x3?file/src/App.vue 常规版本 本部分只写了一些重点代码,心急的彦祖可以直接看 性…

使用chatGPT-4 畅聊量子物理学

与chatGPT深入研究起源、基本概念&#xff0c;以及海森堡、德布罗意、薛定谔、玻尔、爱因斯坦和狄拉克如何得出他们的想法和方程。 1965 年&#xff0c;费曼&#xff08;左&#xff09;与朱利安施温格&#xff08;未显示&#xff09;和朝永信一郎&#xff08;右&#xff09;分享…

机器学习深度学习——文本预处理

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——序列模型&#xff08;NLP启动&#xff01;&#xff09; &#x1f4da;订阅专栏&#xff1a;机器学习&am…

大厂容器云实践之路(二)

3-网易蜂巢的DOCKER实践之路 面临问题 场景分析 如何解决 功能性需求&#xff08;基础&#xff09; 第一步 技术支撑公有化 开发流程 场景分析 功能性需求&#xff08;基础&#xff09; 非功能性需求&#xff08;SLA&#xff09; 第二步 产品技术云端化 开发流程 场景分析…