数据结构之单链表

大家好,我们今天来简单的认识下单链表。

在这里插入图片描述

链表的概念及结构
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。

在这里插入图片描述

单链表就像图中的火车一样,是由一节一节车厢链接起来的,每个车厢都有下一节车厢的节点,也就是我们所说的地址,所以我们的单链表在逻辑上是连续的,但在物理上不一定连续。

链表的实现

构建我们的链表:


typedef struct SListNode
{
	SLNDataType val;
	struct SListNode* next;
}SLNode;

接口的实现:

//打印链表
void SLTPrint(SLNode* phead);

void SLTPushBack(SLNode** pphead,SLNDataType x);

void SLTPushFront(SLNode** pphend, SLNDataType x);

void SLTPopBack(SLNode** pphead);
void SLTPopFront(SLNode** pphead);

SLNode* SLTFind(SLNode* phead, SLNDataType x);

// 在pos的前面插入
void SLTInsert(SLNode** pphead, SLNode* pos, SLNDataType x);

// 删除pos位置
void SLTErase(SLNode** pphead, SLNode* pos);

// 后面插入 后面删除
void SLTInsertAfter(SLNode* pos, SLNDataType x);
void SLTEraseAfter(SLNode* pos);


void SLTDestroy(SLNode** pphead);

打印链表:

void SLTPrint(SLNode* phead)
{
	assert(phead);
	SLNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->val);
		cur = cur->next;
	}
	printf("NULL\n");
}

创建一个新节点:

SLNode* CreateNode(SLNDataType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	newnode->val = x;
	newnode->next = NULL;
	return newnode;
}

对节点进行头插:

void SLTPushFront(SLNode** pphead, SLNDataType x)
{
	assert(pphead);
	assert(*pphead);
	SLNode* newnode = CreateNode(x);
	newnode->next = *pphead;
	*pphead = newnode;

}

对节点进行头插,我们要保证我们的链表不为空我们就进行头插,我们头插的节点的下一个节点就指向我们链表的头结点,而我们的头结点就变成我们的新节点。

尾插:

void SLTPushBack(SLNode** pphead, SLNDataType x)
{
	assert(pphead);
	SLNode* newnode = CreateNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		// 找尾
		SLNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}
}

尾插的话我们得先考虑链表为空的情况,如果链表为空的话,我们的头结点就直接为我们要尾插的节点,如果不为空的话我们就要找到尾节点,我们的遍历条件为tail->next!=NULL,而不是tail!=NULL,前者可以找到尾,而后者我们会使得tail为空,从而出现内存泄漏的情况。

头删:

void SLTPopFront(SLNode** pphead)
{
	assert(*pphead);
	SLNode* tmp = *pphead;
	*pphead = (*pphead)->next;
	free(tmp);
}

头删比较简单,首先保证它不为空,但是我们直接给它释放的话,我们就找不到下一个节点了,所以我们用一个指针来保存它的节点,在使得它指向它的下一个节点,在给它释放就可以了。

尾删:

void SLTPopBack(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	if ((*pphead)->next ==NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLNode* tail = *pphead;
		while (tail->next->next!= NULL)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

如果头结点的下一个为空的话,我们就直接给它释放掉就OK了,但是如果不是头结点的话,我们就找到尾节点,在给它释放掉就可以了。

查找链表:

SLNode* SLTFind(SLNode* phead, SLNDataType x)
{
	SLNode* cur = phead;
	while (cur)
	{
		if (cur->val == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}

	return NULL;
}

在pos的前面插入:

void SLTInsert(SLNode** pphead, SLNode* pos, SLNDataType x)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);
	if (*pphead = pos)
	{
		// 头插
		SLTPushFront(pphead, x);
	}
	else
	{
		SLNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLNode* newnode = CreateNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

在pos前面插入就很简单了,如果我们要插入的位置为头结点的话,我们直接进行头插就可以了,而我们的pos不为头节点我们就进行遍历,找到pos的前一个位置,我们让插入的节点的前一个节点指向我们要插入的节点,而我们要插入的结点的下一个节点指向pos节点。

删除pos位置:

void SLTErase(SLNode** pphead, SLNode* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);

	if (*pphead == pos)
	{
		// 头删
		SLTPopFront(pphead);
	}
	else
	{
		SLNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

这里也一样,如果pos为头结点就进行尾删,如果不为空我们就让pos的前一个节点指向pos的下一个节点就可以了。

pos后面插入:

void SLTInsertAfter(SLNode* pos, SLNDataType x)
{
	assert(pos);
	SLNode* newnode = CreateNode(x);

	newnode->next = pos->next;
	pos->next = newnode;
}

后面插入的情况就比较简单了,我们只要让新节点的下一个指向pos的下一个节点,pos节点的下一个指向新节点就可以了。

pos后面删除:

void SLTEraseAfter(SLNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLNode* tmp = pos->next;
	pos->next = pos->next->next;

	free(tmp);
	tmp = NULL;
}

我们要保存下一个节点防止它找不到下下个节点,我们让下一个节点指向下下个节点,再free掉下一个节点。

销毁链表:

void SLTDestroy(SLNode** pphead)
{
	assert(pphead);

	SLNode* cur = *pphead;
	while (cur)
	{
		SLNode* next = cur->next;
		free(cur);
		cur = next;
	}

	*pphead = NULL;
}

我们同样的要用一个节点来保存下一个节点,我们通过遍历链表来一个一个释放空间,释放后头结点指向下一个节点。

如果对大家有帮助的话,就拜托大家发财的小手点个赞吧,感谢大家的支持。

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

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

相关文章

第12章 PyTorch图像分割代码框架-3:推理与部署

推理模块 模型训练完成后,需要单独再写一个推理模块来供用户测试或者使用,该模块可以命名为test.py或者inference.py,导入训练好的模型文件和待测试的图像,输出该图像的分割结果。inference.py主体部分如代码11-7所示。 代码11-7 …

Linux imu6ull驱动- led

一、GPIO模块结构 开始来啃手册了,打开我们的imx6ull手册。本章我们编写的是GPIO的,打开手册的第28章,这一章就有关于IMX6ULL 的 GPIO 模块结构。 mx6ull一共有5 组 GPIO(GPIO1~GPIO5) GPIO1 有 32 个引脚&…

C/C++输出硬币翻转 2021年6月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C硬币翻转 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C硬币翻转 2021年6月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 假设有N个硬币(N为不大于5000的正整数),从1…

C语言--汉诺塔【内容超级详细】

今天与大家分享一下如何用C语言解决汉诺塔问题。 目录 一.前言 二.找规律⭐ 三.总结⭐⭐⭐ 四.代码实现⭐⭐ 一.前言 有一部很好看的电影《猩球崛起》⭐,说呀,人类为了抗击癌症发明了一种药物🍗,然后给猩猩做了实验&#xff0…

2020年五一杯数学建模A题煤炭价格预测问题解题全过程文档及程序

2020年五一杯数学建模 A题 煤炭价格预测问题 原题再现 煤炭属于大宗商品,煤炭价格既受国家相关部门的监管,又受国内煤炭市场的影响。除此之外,气候变化、出行方式、能源消耗方式、国际煤炭市场等其他因素也会影响煤炭价格。请完成如下问题。…

canvas 简单直线轨迹运动与线性插值计算

canvas 简单直线轨迹运动与线性插值计算 一、canvas 直线轨迹运行 添加 canvas 语法提示 通过/** type {HTMLCanvasElement} */代码块 来添加canvas的语法提示 <body><canvas id"canvas"></canvas> </body> <script>/** type {HTM…

软件模拟SPI协议的理解和使用编写W25Q64

SPI软件模拟的时序 SPI协议中&#xff0c;NSS、SCK、MOSI由主机产生&#xff0c;MISO由从机产生&#xff0c;在SCK每个时钟周期MOSI、MISO传输一位数据&#xff0c;数据的输入输出是同时进行的&#xff0c;所以读写数据也可以视作交换数据。所以读写时对数据位的控制都是用同一…

ke10javaweb停更

<jsp:getProperty property"isval" name "username"/> property来修改属性,name是类 所以如果调用tip在前面那么就是没有设置值 证明是先到java里面去运转

AI编程工具:一站式编程解决方案,引领AI编程新时代

在人工智能的巨浪之下&#xff0c;编程领域正在经历一场深刻的转型。这场转型的核心&#xff0c;就是AI智能编程工具的出现。它们为开发者提供了一种全新的编程方式&#xff0c;极大地提高了编程效率。在这场变革中&#xff0c;DevChat无疑是引领者之一。 一、DevChat&#xf…

计算机毕业设计 基于SpringBoot高校毕业与学位资格审核系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

AMD发布大小核 CPU,6核心直接砍成单核了

2022年 Intel 第12代酷睿发布&#xff0c;PE 大小核设计被正式带到了 PC 上。 P-Core 也就是传统的大核有着高性能、高功耗&#xff0c;而 E-Core 小核则是更讲究能效比以更低频率运行。 虽说小蝾也曾有对 Windows 调度方面的怀疑&#xff0c;但多线程性能确实实打实证明了其优…

2023年最受欢迎的9款产品原型工具大揭秘!

1.Pop (Prototyping on Paper) 价格&#xff1a;免费试用30天专业版960RMB/人/年 学习曲线&#xff1a;低 简介&#xff1a;POP是设计界面的原型工具&#xff0c;适用于iOS和Android平台。在POP的帮助下&#xff0c;开发人员或设计师只需在纸上简单地描述创意或想法&#xff…

SPI简介及FPGA通用MOSI模块实现

简介 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外围设备接口&#xff09;通讯协议&#xff0c;是Motorola公司提出的一种同步串行接口技术。是一种高速、全双工、同步通信总线。在芯片中只占用四根管脚用来控制及数据传输。 优缺点&#xff1a; SPI通讯协…

向量数据库:释放数据潜能,重塑信息世界

前言 想必各位开发者一定使用过关系型数据库MySQL去存储我们的项目的数据&#xff0c;也有部分人使用过非关系型数据库Redis去存储我们的一些热点数据作为缓存&#xff0c;提高我们系统的响应速度&#xff0c;减小我们MySQL的压力。那么你有听说过向量数据库吗&#xff1f;知道…

白嫖阿里云服务器教程来了,薅秃阿里云!

白嫖阿里云服务器攻略来了&#xff0c;在阿里云免费试用中心可以申请免费服务器&#xff0c;但是阿里云百科不建议选择免费的&#xff0c;只有3个月使用时长&#xff0c;选择99元服务器不是更香&#xff0c;2核2G配置3M固定带宽&#xff0c;一年99元&#xff0c;重点是新老用户…

【Linux】-文件操作(重定向、缓冲区以及Linux下一切皆文件的详解)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

如何自己实现一个丝滑的流程图绘制工具(九) 自定义连接线

背景 产品又有更近的想法了&#xff0c;bpmn-js的连接线你用的时候是看不到的&#xff0c;也就是你从左侧点击连接线的没有线随鼠标移动. 但是产品想要看得见的连接线移动拖拽。 咩有办法&#xff0c;不能换框架&#xff0c;那就只能自己实现啦&#xff01; 思路&#xff1a; …

06-MySQL-进阶-视图存储函数存储过程触发器

涉及资料 链接&#xff1a;https://pan.baidu.com/s/1M1oXN_pH3RGADx90ZFbfLQ?pwdCoke 提取码&#xff1a;Coke 一、视图 数据准备 create table student(id int auto_increment comment 主键ID primary key,name varchar(10) null comment 姓名,no varchar(10) null co…

JDBC(一)

第1章&#xff1a;JDBC概述 1.1 数据的持久化 持久化(persistence)&#xff1a;把数据保存到可掉电式存储设备中以供之后使用。大多数情况下&#xff0c;特别是企业级应用&#xff0c;数据持久化意味着将内存中的数据保存到硬盘上**&#xff0c;而持久化的实现过程大多通过各种…

利用中断做数码表

功能要求:1.按下KEY1&#xff0c;显示数字开始每0.5秒加1&#xff0c;加到&#xff08;10学号&#xff09;返回0&#xff0c;0显示2秒后继续开始重复加1。 2. 任何时候按下KEY2数字清零&#xff0c;并停止加1。 3. KEY1和KEY2分别采用查询和外部中断方式。 要求程序中有硬件…
最新文章