链表之单链表

news2024/11/24 19:45:32

上一篇博客我们学习了线性表中的顺序表,这一篇博客让我们继续往下了解线性表的链表,链表分为好几种结构,活不多说,让我们开始学习吧!


目录

1.链表

2.链表的结构

3.单链表的实现


1.链表

1.概念:它是一种物理存储结构上非连续非顺序的存储结构,数据元素的逻辑顺序是通过链                表中的指针链接次序实现的。它在空间上,按需给空间,不要求物理空间的连续,                和顺序表不同,它头部和中间的数据的插入就不需要挪动数据。链表的实现是通过                指针的。

2.有些老铁可能不明白什么是物理结构,它就是在内存中实实在在的存储形式。

什么是不连续非顺序,我们画图来给大家解释一下:

在这些节点中间,我们可以插入新的节点,又是新的地址,所以说它不是按顺序走的。这些节点在内存中,可能这有一个节点,也可能那有一个节点,但它们彼此之间通过指针相连接,只要指针不断,就可以找到下一个节点。

3.链表只能一个一个诶个访问,只能从头找,因为一旦它找到下一个节点,它就不知道上一个节点的位置了(双向链表可以找到上一个,我们到了那个章节在继续学习)。这时,又显示出顺序表的好处了,因为它可以直接定位到要查找数据的位置,但是它会造成空间的浪费,所以说有好有坏,需要大家自己体会。

2.链表的结构

链表分为八种结构,在这里先给大家一个总体的框架,方便接下来的学习:

单链表,双链表,不带头链表,带头链表,循环链表,不循环链表,这六种链表构成了链表的八种结构,分别是:

1.单向不带头不循环链表

2.单向不带头循环链表

3.单向带头不循环链表

4.单向带头循环链表

5.双向不带头不循环链表

6.双向不带头循环链表

7.双向带头不循环链表

8.双向带头循环链表

我们今天在这里会实现第一种结构,单向不带头不循环链表,相信通过这个链表的实现,大家可以把2,3,4种结构都实现。

3.单链表的实现

现在我们来实现这个单链表,可以类比顺序表写,这一部分的代码都大差不差,具体要看怎么实现。

SList.h文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int ALTDataType;

//创建结构体,用来创建链表组成元素
typedef struct SListNode
{
	ALTDataType data;//链表数据
	struct SListNode* next;//链表指向下一个元素的指针,指向下一个节点的位置
}SLN;

//开辟空间来存入数据
SLN* BuySListNode(ALTDataType x);
//打印链表
void SListPrint(SLN* phead);
//头插
void sListPushFront(SLN** pphead, ALTDataType x);
//尾插
void sListPushBack(SLN** pphead, ALTDataType x);
//头删
void sListPopFront(SLN** pphead);
//尾删
void sListPopBack(SLN** pphead);
//查找链表
SLN* sListFind(SLN* phead, ALTDataType x);
//修改对应链表位置的数据
void sListModify(SLN* phead, SLN* pos, ALTDataType x, ALTDataType y);
//任意位置的插入,在pos位置的前一个位置插入
void sListInsert(SLN** pphead, SLN* pos, ALTDataType x);
//任意位置的删除
void sListErase(SLN** pphead, SLN* pos);
//销毁链表
void destorySList(SLN* phead);

SList.c文件

#include"SList.h"

//开辟空间来存入数据
SLN* BuySListNode(ALTDataType x)
{
	SLN* newnode = (SLN*)malloc(sizeof(SLN));
	if (newnode == NULL)
	{
		perror("malloc");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

//打印链表
void SListPrint(SLN* phead)
{
	assert(phead);
	SLN* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

//头插
//想要头插,我们要把新节点的地址给到头节点,再把新节点定义为新的头节点
void sListPushFront(SLN** pphead, ALTDataType x)
{
	SLN* newnode = BuySListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

//尾插
void sListPushBack(SLN** pphead, ALTDataType x)
{
	SLN* newnode = BuySListNode(x);
	//若一开始链表为空,我们直接插入一个新节点
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	//我们要创建一个变量,找到链表的尾端,从尾端插入
	SLN* tail = *pphead;
	while (tail->next)
	{
		tail = tail->next;
	}
	tail->next = newnode;//尾节点链接新节点
}

//头删
void sListPopFront(SLN** pphead)
{
	assert(*pphead);
	SLN* next = (*pphead)->next;//*小于->的优先级,编译器不通过
	free(*pphead);
	*pphead = NULL;
	*pphead = next;
}
//尾删
void sListPopBack(SLN** pphead)
{
	assert(*pphead);
	//当只有一个节点时
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}
	SLN* tail = *pphead;
	SLN* prev = NULL;
	while (tail->next)
	{
		prev = tail;
		tail = tail->next;
	}
	free(tail);
	tail = NULL;
	prev->next = NULL;
}
//查找链表
SLN* sListFind(SLN* phead, ALTDataType x)
{
	assert(phead);
	SLN* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
//修改对应链表位置的数据
void sListModify(SLN* phead, SLN* pos, ALTDataType x, ALTDataType y)
{
	pos = sListFind(phead, x);
	pos->data = y;
}
//任意位置的插入,在pos位置的前一个位置插入
void sListInsert(SLN** pphead, SLN* pos, ALTDataType x)
{
	if (pos == *pphead)
	{
		sListPushFront(pphead, x);
		return;
	}
	SLN* newnode = BuySListNode(x);
	SLN* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	prev->next = newnode;
	newnode->next = pos;
}
//任意位置的删除,删除pos位置的值
void sListErase(SLN** pphead, SLN* pos)
{
	if (pos == *pphead)
	{
		sListPopFront(pphead);
		return;
	}
	SLN* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	prev->next = pos->next;
	free(pos);
	pos = NULL;
}
//销毁链表,这些空间,我们要一个一个释放,防止内存泄漏
void destorySList(SLN* phead)
{
	assert(phead);
	SLN* tail = phead->next;
	while (tail)
	{
		SLN* next = tail->next;
		free(tail);
		tail = NULL;
		tail = next;
	}
	free(phead);
	phead = NULL;
}

test.c文件

#include"SList.h"


void Test1()
{
	SLN* plist = NULL;
	SLN* pos = NULL;
	sListPushFront(&plist, 4);
	sListPushFront(&plist, 3);
	sListPushFront(&plist, 2);
	sListPushFront(&plist, 1);
	SListPrint(plist);

	sListPushBack(&plist, 5);
	sListPushBack(&plist, 6);
	sListPushBack(&plist, 7);
	sListPushBack(&plist, 8);
	SListPrint(plist);

	sListPopFront(&plist);
	sListPopFront(&plist);
	SListPrint(plist);

	sListPopBack(&plist);
	sListPopBack(&plist);
	SListPrint(plist);

	pos = sListFind(plist, 5);
	if (pos == NULL)
	{
		printf("找不到该数据\n");
	}
	else
	{
		printf("已找到该数据,现在进行修改\n");
		sListModify(plist, pos, 5, 50);
	}
	SListPrint(plist);

	pos = sListFind(plist, 50);
	if (pos == NULL)
	{
		printf("找不到该数据\n");
	}
	else
	{
		printf("已找到该数据,现在进行在pos前插入数据\n");
		sListInsert(&plist, pos, 20);
	}
	SListPrint(plist);

	pos = sListFind(plist, 20);
	if (pos == NULL)
	{
		printf("找不到该数据\n");
	}
	else
	{
		printf("已找到该数据,现在进行对pos位置数据的删除\n");
		sListErase(&plist, pos);
	}
	SListPrint(plist);

	destorySList(plist);
	printf("链表已销毁\n");
}
int main()
{
	Test1();
	return 0;
}

结果:大家下去还是要自己敲一遍代码,才能做到掌握


好了,今天的内容就是这些,我们下期再见铁汁们!

感谢品读!!!

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

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

相关文章

快速跨国传输怎么实现?

在当今全球化的商业舞台上&#xff0c;迅速且安全地跨国界传输大型文件已经成为企业运营的一个核心环节。但是&#xff0c;这一过程往往面临速度缓慢和安全隐患的问题&#xff0c;这些问题严重地影响了企业的工作效率和数据的安全性。小编将会深入探讨企业在进行跨国大文件传输…

揭秘!自定义三维模型如何在RflySim中实现仿真(三)

一.技术背景 揭秘&#xff01;自定义三维模型如何在RflySim中实现仿真&#xff08;一&#xff09; 揭秘&#xff01;自定义三维模型如何在RflySim中实现仿真&#xff08;二&#xff09; 上两篇文章我们学习了自定义三维模型如何在RflySim中实现仿真和三维场景导入RflySim的实…

ssm023实验室耗材管理系统设计与实现+jsp

实验室耗材管理系统的设计与实现 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对实验室耗材信息管理混乱&#xff…

阴影画图转html

深受启发 https://segmentfault.com/a/1190000014943400?utm_sourcetag-newest https://gitee.com/yun-36/shadow-drawing 通过File对象&#xff0c;读成dataURL&#xff0c;生成图片&#xff0c;挂到canvas&#xff0c;生成图片文件对应的rgba数据像素点信息&#xff0c;处理…

【机器学习】科学库使用第3篇:机器学习概述,学习目标【附代码文档】

机器学习&#xff08;科学计算库&#xff09;完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;机器学习&#xff08;常用科学计算库的使用&#xff09;基础定位、目标&#xff0c;机器学习概述定位,目标,学习目标,学习目标,1 人工智能应用场景,2 人工智能小…

centOS如何升级python

centOS下升级python版本的详细步骤 1、可利用linux自带下载工具wget下载&#xff0c;如下所示&#xff1a; 笔者安装的是最小centos系统&#xff0c;所以使用编译命令前&#xff0c;必须安装wget服务&#xff0c;读者如果安装的是界面centos系统&#xff0c;或者使用过编译工具…

搭建跨境电商电商独立站如何接入1688平台API接口|通过1688API接口采集商品通过链接搜索商品下单

接口设计|接口接入 对于mall项目中商品模块的接口设计&#xff0c;大家可以参考项目的Swagger接口文档&#xff0c;以Pms开头的接口就是商品模块对应的接口。 参数说明 通用参数说明 参数不要乱传&#xff0c;否则不管成功失败都会扣费url说明……d.cn/平台/API类型/ 平台&…

【御控物联】JSON结构数据转换在物流调度系统中的应用(场景案例三)

文章目录 一、前言二、场景概述三、解决方案四、在线转换工具五、技术资料 一、前言 物流调度是每个生产厂区必不可少的一个环节&#xff0c;主要包括线边物流和智能仓储。线边物流是指将物料定时、定点、定量配送到生产作业一线的环节&#xff0c;其包括从集中仓库到线边仓、…

C++的字节对齐

什么是字节对齐 参考什么是字节对齐&#xff0c;为什么要对齐? 现代计算机中&#xff0c;内存空间按照字节划分&#xff0c;理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问&#xff0c;这就需要各种类型数据按照一定的规…

数据结构(六)——图的存储及基本操作

6.2 图的存储及基本操作 6.2.1 邻接矩阵法 邻接矩阵存储无向图、有向图 #define MaxVertexNum 100 //顶点数目的最大值typedef struct{char Vex[MaxVertexNum]; //顶点表int Edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵&#xff0c;边表int vexnum,arcnum; //图的当前…

pygame--坦克大战(一)

项目搭建 本游戏主要分为两个对象,分别是我方坦克和敌方坦克。用户可以通过控制我方的坦克来摧毁敌方的坦克保护自己的“家”,把所有的敌方坦克消灭完达到胜利。敌方的坦克在初始的时候是默认5个的(这可以自己设置),当然,如果我方坦克被敌方坦克的子弹打中,游戏结束。从…

Type-c转USBA3.0芯片 USBA3.0转Type-c芯片(USB3.1GEN2 多路切换Switch芯片) VL162

VL162具有CC功能的USB Type-C数据开关USB 3.1 Gen2 (10Gbps) VL162 带CC功能的USB Type-C数据开关 支持最高10Gbps 2差分通道&#xff0c;2:1 MUX/DeMUX 兼容10Gbps USB3.1 Gen2 低功耗&#xff0c;6mW在设备模式下有效 高直流共模电压&#xff0c;支持2.0V 28针QFN 3.5 x 4.5m…

软件测试(二)--测试用例

一、什么是用例: 用例就是用户使用案例的简称。以手机用例为例&#xff1a; 1.是否能开机&#xff1a;打开手机按下电源键3秒&#xff0c;看是否能开机。 2.验证内存&#xff1a;打开手机设置查看内存是否为64G. 3.验证屏幕&#xff1a;打开手机在白屏背景下检查屏幕是否有黑点…

MCU配置的1106模块与1102模块功能差异分析

在现代工业自动化和智能控制领域&#xff0c;微控制器(MCU)扮演着至关重要的角色。而在MCU的配置中&#xff0c;选择适合的传感器采集模块是确保数据采集准确性和多样性的关键。其中&#xff0c;1106模块和1102模块作为两种常见的采集模块&#xff0c;各自具有独特的功能特点和…

TSINGSEE青犀推出河道/河湖/水域治理视频AI智能解决方案

一、方案背景 “十四五”时期&#xff0c;在面源污染防治等方面实现突破&#xff0c;实现主要水污染排放总量持续减少&#xff0c;水生态环境持续改善等任务艰巨。进一步完善流域综合治理体系&#xff0c;提升流域水环境综合治理能力和水平&#xff0c;更好适应新阶段发展需求…

Mac OS上使用matplotlib库显示中文字体

文章目录 问题描述解决步骤参考文章 问题描述 如果我们想要使用matplotlib画图的话&#xff0c;可能会出现下面的这种warning: UserWarning: Glyph 24212 (\N{CJK UNIFIED IDEOGRAPH-5E94}) missing from current font.解决步骤 解决这个问题&#xff0c;可以按照下面的做法…

Rust所有权和Move关键字使用和含义讲解,以及Arc和Mutex使用

Rust 所有权规则 一个值只能被一个变量所拥有&#xff0c;这个变量被称为所有者。 一个值同一时刻只能有一个所有者&#xff0c;也就是说不能有两个变量拥有相同的值。所以对应变量赋值、参数传递、函数返回等行为&#xff0c;旧的所有者会把值的所有权转移给新的所有者&#…

【开发、测试】接口规范与测试

接口测试基础 url 是互联网标准资源地址&#xff0c;称为统一资源定位符 组成&#xff1a;协议&#xff0c;服务器地址&#xff0c;端口号 HTTP协议 HTTP&#xff1a;超文本传输协议&#xff0c;基于请求与响应的应用层协议 作用&#xff1a;规定了客户端和服务器之间的信…

Spring IOC控制反转、DI注入以及配置

1.使用xml的方式进行配置IOC容器&#xff0c;首先引入依赖 在Resource资源下配置&#xff0c;applicationContext.xml ,刷新mevan后可以直接选择配置spring.xml文件 <!-- spring核心用来管理bean --><dependency><groupId>org.springframework</g…

对【AI技术创业】有哪些机会进行分析和引导

文章目录 方向一&#xff1a;行业解决方案,以下是一些常见的行业解决方案&#xff1a;方向二&#xff1a;智能产品和服务,以下是一些智能产品和服务的示例&#xff1a;方向三&#xff1a;教育和培训 1.智能客户服务&#xff1a; 利用自然语言处理&#xff08;NLP&#xff09;和…