C语言数据结构基础-单链表

1.链表概念

       在前面的学习中,我们知道了线性表,其中逻辑结构与物理结构都连续的叫顺序表,那么:

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

2.链表组成

单链表元素(节点)由保存的数据和下个单元的地址组成

 

//结点结构体的定义
struct SListNode{
  int data;
  struct SListNode* next;
};

(node就是结点的意思)

国际惯例,我们进行typdef

typedef struct SListNode{
  int data;
  struct SListNode* next;
}SLTNode;

那么此时我们可不可以在其中定义next的时候也用SLTNode呢?

SLTNode* next;

       当然是不可以的,此时使用的SLTNode还未被定义,编译器还未能识别,使用了就会报错

为什么要用malloc开辟空间?

为了之后删除(使用free函数释放指针指向的空间)的时候方便,进行初始化时用malloc给每一个节点开辟空间

3.单链表各功能的实现

为了便于链表结点的创建和初始化,我们将其初始功能进行封装

SLTNode* SLTBuyNode(SLTDataType x) {
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL) {
		perror("malloc fail!");
		exit(1);
	}
	newnode->next = NULL;
	newnode->data = x;
	return newnode;
}
 1.尾差

基于顺序表的经验,大概分为两种情况,一种是链表为空,另一种是链表不为空

我们首先传入该链表的头节点,通过直接链接或者先遍历再链接。

传一个指针进函数,对指针进行操作(每一个结点都有元素与其指针等级),那么以上函数就算传值调用,并不能让phead真正等于newnode 

此处的传指针就是传值调用,指针作为变量来修改,就应该传指针的地址,才能达到传址调用的目的。

传递一个指针,可以在函数内部直接修改该指针指向空间的内容,但是想修改、操作传递来的指针,就必须传该指针的指针,才能通过该指针的指针来修改指针的内容。 

       先让创建的新结构体的next找到现在的phead(也就是*pphead,因为函数中不再存在phead这个变量)

再把现在处于第一个的结构体(我们刚刚自己创建的newnode)的地址给到phead

形参是实参的拷贝。

void SLTPushBack(SLTNode** pphead, SLTDataType x) {
	assert(pphead);

	SLTNode* newnode = SLTBuyNode(x);

	//链表为空,新节点作为phead
	if (*pphead == NULL) {
		*pphead = newnode;
		return;
	}
	//链表不为空,找尾节点
	SLTNode* ptail = *pphead;
	while (ptail->next)
	{
		ptail = ptail->next;
	}
	//ptail就是尾节点
	ptail->next = newnode;
}

为了便于主函数的调用和检验,我们写出能打印其数据的函数

void SLTPrint(SLTNode* phead) {
	assert(phead);
	SLTNode* pos = phead;
	while (pos) {
		printf("%d->",pos->data);
		pos = pos->next;
	}
	printf("NULL");
}

这样就能检验我们的尾插功能了。 

2.头插

此处同理,我们任然需要传一个二级指针,通过二级指针对链表进行修改。

依然是分两种情况,实现如下:

void SLTPushFront(SLTNode** pphead, SLTDataType x) {
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
    //若为空
	if (*pphead == NULL) {
		*pphead = newnode;
		return;
	}
	//链接newnode 和 *pphead
	newnode->next = *pphead;
	*pphead = newnode;
}

能否调换以下两句的顺序? 

当然不行,否则新节点将自己的地址赋给了自己的next。

由此可见,链表的实现,重在理清个节点之间的链接顺序。

3.尾删

释放空间,让原本倒数第二个结点的next指向NULL(先free,再置NULL)

多个节点时,我们需要先遍历链表找到最后一个节点的前驱节点ptail(原来的倒数第二个节点),删除最后一个节点的同时改变前驱节点的next的值

但如果只有一个节点呢?

if ((*pphead)->next == NULL) {
	free(*pphead);
	*pphead = NULL;
	return;
}

    所以直接先free再置NULL即可 ,但请注意->和*的优先级不同,箭头是最高优先级,所以需要使用括号

void SLTPopBack(SLTNode** pphead) {
	assert(pphead);
	//没有节点时
	assert(*pphead);
	//只有一个节点时
	if ((*pphead)->next) {
		free(*pphead);
		*pphead = NULL;
		return;
	}
	//多个节点时
	SLTNode* ptail = *pphead;
	while (ptail->next->next) {//很明显,只有一个节点的时候过不了,那么我们就需要在多个节点之前写出只有一个节点的情况
		ptail = ptail->next;
	}
	free(ptail->next);
	ptail->next = NULL;
}

尽管看上去是先写的一个节点,再写的多个节点,但正常逻辑应该是先写多个(通常情况)再考虑一个(特殊情况)

tips:

遍历链表与找链表尾结点是不一样的

(补充一下遍历链表的方法) 

SLTNode* ptail = *pphead;
SLTNode* prev = NULL;
while (ptail->next)
{
	prev = ptail;
	ptail = ptail->next;
}
4.头删

如果链表已经为空的话应该直接退出,所以依然分三种情况考虑

void SLTPopFront(SLTNode** pphead) {
	assert(pphead);
	//没有节点 一个节点 多个节点
	assert(*pphead);

	SLTNode* tmp = *pphead;
	*pphead = (*pphead)->next;
	free(tmp);
	tmp = NULL;
	//发现此时一个节点和多个节点都能通过这段代码
}

依然是处理pphead和pphead->next的关系,此处又有一个小技巧,如过发现不能很好的直接通过等式调整各个指针所指向的位置,可以通过建立新的变量拷贝需要处理的数据。 

5.指定位置前后的插入

为了能找到指定的位置,我们先写出一个查找函数

SLTNode* SLTFind(SLTNode* phead, SLTDataType x) {
	assert(phead);
	while (phead->next) {
		if (phead->data == x) {
			return phead;
		}
		phead = phead->next;
	}
	//没有找到
	return NULL;
}

 为什么要断言链表不为空?因为如果链表为空,传进来的pos也必须为空,矛盾。

pos应当是已知链表(首节点地址为*pphead的)一个具体特定结点,而非NULL

当然,此处也可以不传二级指针只传一级指针,因为我们也可以不需要对传入的指针进行操作,但是为了接口的一致性,也可以都使用二级指针接口

void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = pos->next;
	pos->next=newnode;
}

void SLTInsertBefore(SLTNode* phead, SLTNode* pos, SLTDataType x) {
	assert(pos);
	assert(phead);
	
	if (pos == phead) {
		SLTPushFront(&phead, x);
		return;
	}

	SLTNode* newnode = SLTBuyNode(x);
	SLTNode* prev = phead;
	while (prev->next != pos) {
		prev = prev->next;
	}
	newnode->next = pos;
	prev->next = newnode;
	
}

为什么在指定位置前插入数据需要头结点的位置,而指定位置后的不需要呢(指定位置之前插入需要三个参数,指定位置之后插入需要两个参数)?

因为根据单链表的特性,除了最后一个节点,所有节点都能通过自己找到下一个节点,但是找不到上一个节点,所以当我们需要再指定位置之前插入数据时,就需要遍历链表来找到指定位置。

6.删除指定位置之后的节点

 此处的条件为pos->next不为空,具体操作就是链接pos,pos->next,pos->next->next之间的关系

void SLTEraseAfter(SLTNode* pos) {
	assert(pos);
	if (pos->next == NULL) {
		return;
	}
	//pos pos->next pos->next->next
	SLTNode* tmp = pos->next;
	pos->next = pos->next->next;
	free(pos->next);
	pos->next == NULL;
}
7.删除指定位置的节点

同理

void SLTErase(SLTNode* phead, SLTNode* pos) {
	assert(phead);
	assert(pos);
	//刚好是头则执行头删
	if (phead == pos) {
		SLTPopFront(&phead);
		return;
	}
	while (phead->next != pos) {
		phead = phead->next;
	}
	phead->next = pos->next;
	free(pos);
	pos = NULL;
}

6,7检测如下 

4.链表分类

上文的单链表Slist就是singel linked list(单向不带头不循环链表)

依据不同的特点,共有八种链表

前文提到的头结点与“带头”的头不一样,前者为第一个有效节点,后者是所谓的哨兵位,不存储有效数据 

       虽然链表种类非常多,但是最实用的只有:单链表、双向链表(带头双向循环链表)

本篇中,已经实现了单链表的大多数功能。

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

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

相关文章

线性稳压器电路,用于各种电视机、收录机、电子仪器、设备的稳压电源上,内置短路保护电路,热保护电路——78MXX

78MXX系列是用于各种电视机、收录机、电子仪器、设备的稳压电源电路。包括78M05、78M06、 78M08、 78M09、 78M10、 78M12、 78M15。 主要特点: ● 极限输出电流: 0.5A ● 固定输出电压: 5V、6V、8V、9V、10V、 12V、 15V ● 内置短路保护电路 ● 内置热保护电路 …

云原生精品资料合集(附下载)

云计算是产业数字化转型的关键基础设施,以基础设施资源为中心的云搬迁时代接近尾声,以应用价值为中心的云原生时代已经到,所以IT人员学习云原生正当时!最近跟各位大神征集了云原生的教程,行业报告和最佳实践,总有一款适…

python web框架fastapi模板渲染--Jinja2使用技巧总结

文章目录 1.jinja2模板1.1、jinja2 的变量1.1.1 列表类型数据渲染1.1.2 字典类型数据渲染 2. jinja2 的过滤器3. jinja2 的控制结构3.1、分支控制3.2、循环控制 1.jinja2模板 要了解jinja2,那么需要先理解模板的概念。模板在Python的web开发中⼴泛使⽤,…

Unity 常用操作

2D素材网站 https://craftpix.net/ https://itch.io/game-assets/tag-2d/tag-backgrounds 3D素材资源网址 https://www.mixamo.com/#/ 场景常用操作: 快捷键:QWER Q:Q键或鼠标中键,可以拉动场景。 W:选中物体后&…

【QT+QGIS跨平台编译】之五十六:【QGIS_CORE跨平台编译】—【qgsmeshcalclexer.cpp生成】

文章目录 一、Flex二、生成来源三、构建过程一、Flex Flex (fast lexical analyser generator) 是 Lex 的另一个替代品。它经常和自由软件 Bison 语法分析器生成器 一起使用。Flex 最初由 Vern Paxson 于 1987 年用 C 语言写成。 “flex 是一个生成扫描器的工具,能够识别文本中…

基于springboot实现在线考试系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现在线考试系统演示 摘要 时代在变化,科技技术以无法预测的速度在达到新的高度,并且被应用于社会生活的各个领域,随着生活的加快,也使很多潜在的点逐渐突显出来,社会对于人才的要总是非常迫切的&…

18.HTTPS和身份验证

平凡也就两个字: 懒和惰; 成功也就两个字: 苦和勤; 优秀也就两个字: 你和我。 跟着我从0学习JAVA、spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美! 关注微信公众号【 IT特靠谱 】,每天都会分享技术心得~ …

关于电脑一天24小时多少度电电脑的一天用电量计算

随着这几年物价的上涨,一些地区的电价越来越高,而我们经常需要使用电脑,那么一台电脑一天24小时用多少度电呢? 如何计算电脑一天的用电量? 让我们跟随小编来了解更多吧。 1、功耗、主机箱功耗 现在的计算机中&#xf…

【python基础学习03课_python的列表】

列表 一、列表的定义 列表 -- 一种将多个数据组合在一起的容器(数据结构)标识符:[]关键字:list tips: 变量的名称可以自定义,但是不要与文件名、关键字、后面要学到的类、方法等等重复 1、打印空列表 列表是一个…

洛谷题单-动态规划的引入

动态规划的引入 P1216 [USACO1.5] [IOI1994]数字三角形 Number Triangles 题解解法一: 从上往下推用dp P1048 [NOIP2005 普及组] 采药 题解解法一: 一维01背包 P2196 [NOIP1996 提高组] 挖地雷 题解解法一: dfs暴搜解法二: dp解法三: 树形dp P1434 [SHOI2002] 滑雪解法一: 记忆…

c++学习记录 vector容器—插入和删除

函数原型: push_back(ele); //尾部插入元素elepop_back(); //删除最后一个元素insert(const_iterator pos,ele); …

2024年腾讯云值得买的云服务器配置推荐,前十名!

腾讯云服务器多少钱一年?62元一年起,2核2G3M配置,腾讯云2核4G5M轻量应用服务器218元一年、756元3年,4核16G12M服务器32元1个月、312元一年,8核32G22M服务器115元1个月、345元3个月,腾讯云服务器网txyfwq.co…

华为数通方向HCIP-DataCom H12-821题库(单选题:501-520)

第501题 三台交换机运行RSTP协议,拓扑和配置情况如图所示。那么以下关于根桥的描述,正确的是哪一项? A、根桥是SWA B、根桥是SWB C、根桥是SWC D、根桥无法确定 参考答案:A 第502题 在华为设备中,以下哪一个命令可以实现BFD与静态默认路由联动? A、ip route-static 0.…

嵌入式开发——面试题操作系统(调度算法)

linux7种进程调度算法 1:先来先服务(FCFS)调度算法 原理:按照进程进入就绪队列的先后次序进行选择。对于进程调度来说,一旦一个进程得到处理机会,它就一直运行下去,直到该进程完成任务或者因等…

“祖传代码”:程序员的“宝藏图”还是“地雷区”?

程序员对“祖传代码”的看法可能因个人经验、技能和项目需求等因素而有所不同。但无论如何,祖传代码的背后都有一段段啼笑皆非或者令人深省的故事。 一、程序员对祖传代码的看法 结合笔者以及身边形形色色大猿小猿的态度,浅浅罗列以下看法: 恐惧和厌恶…

day03_登录注销(前端接入登录,异常处理, 图片验证码,获取用户信息接口,退出功能)

文章目录 1. 前端接入登录1.1 修改前端代码1.2 跨域请求1.2.1 跨域请求简介1.2.2 COSR概述CORS简介CORS原理 1.2.3 CORS解决跨域 2. 异常处理2.1 提示空消息分析2.2 系统异常分类2.3 异常处理2.2.1 方案一2.2.2 方案二 3. 图片验证码3.1 图片验证码意义3.2 实现思路3.3 后端接口…

微服务 人工智能AI 物联网智慧工地云平台源码

目录 ​编辑 智慧工地架构 智慧工地系统 智慧工地云平台功能模块 1、基础数据管理 2、考勤管理 3、安全隐患管理 4、视频监控 5、塔吊监控 6、升降机监控 7、移动端数据推送 智慧工地管理平台子系统构成 智慧工地物联网解决方案,对工地施工安全人员、设…

三种食物轮流吃,睡眠时间又长又香!

睡眠质量一直是人们关注的焦点,而饮食则被认为是影响睡眠的重要因素之一。近年来,有一种食物搭配方法备受瞩目,据说可以让人们的睡眠时间又长又香。这种方法并不复杂,只需要轮流食用三种特定食物,就能有效改善睡眠质量…

window server 2012 r2配置多用户远程登录

window server2012r2配置多用户远程登录 注:window系统默认只允许一个用户登录,但在配置中可以设置多用户同时远程。非特殊情况不建议设置多用户远程,以防数据丢失,或数据篡改无法排查。 1、桌面winr打开gpedit.msc 2、点击管理…

BigTime 2024:多人对战新期待,链游迎来强势回归

随着2024年加密货币市场行情回暖,区块链游戏正成为行业中充满活力的领域。截至2023年,该市场的价值已超过30亿美元,并预计到2030年将达到900亿美元。这种增长部分源于投资的增加和NFT的广泛应用。同时,融合传统游戏元素与区块链技…
最新文章