数据结构——线性数据结构(C语言实现单链表详解)

news2024/10/1 15:28:34

什么是单链表?

单链表就是一种线性的链式数据结构。单链表通过节点来存储线性数据的,单链表不要求连续的物理空间来存储数据。但是,单链表在逻辑结构上是连续的。通常,会有一个头指针指向单链表的首结点因为单链表的结点会存储一下个结点的地址,以便于访问后面的结点,单链表的尾结点存储的是NULL。
![在这里插入图片描述](https://img-blog.csdnimg.cn/84b894a5a8964e45906498b8a8eff75d.png

在这里插入图片描述
我们可以将单链表理解成类似于通过铁链连接在一起的火车,头结点也就是火车头,它是单链表最关键的结点,单链表的一切操作都离不开它。通常它被一个头指针或者哨兵位头结点指向。链表的尾结点是指向NULL的。

单链表的优缺点

优点

单链表不需要连续的物理空间来存放数据,可以大大的突破线性表的物理空间上的制约。单链表从头结点增删查改数据效率高。学习单链表可以提升我们对于编程语言的理解。

缺点

单链表由于需要通过当前结点内存放的下一个结点的地址才能够找到下一个结点,当我们遍历链表和对链表尾结点进行增删查改是效率一般。并且对单链表某个结点进行增删查改操作时,需要对单链表的物理结构和逻辑结构有一个清晰的理解。

单链表基本功能的实现

单链表定义

首先,我们需要知道,单链表内所需要的数据有两种,一种是数据,还有就是下一个节点的指针。所以我们需要定义一个结构体。

typedef int SLTDataType;//重命名单链表的数据
//便于不同数据类型的切换
typedef struct SLTNode
{
	SLTDataType data;
	struct SLTNode* next;
	//SLTNode* next//错误
	//改写法C语言是不支持的
	//struct SLTNode//错误
}SLTNode;

单链表插入数据

想要了解一种数据结构,就要理解它的最基本的增删查改逻辑,下面我就先从插入数据先手。

开辟新节点

在插入链表新节点前,我们可以先写一个接口用于创建一个新的结点。创建后将结点初始化一下,初始化数据为我们所指定的数据,并将下一个结点初始化成NULL,以便于我们使用。

SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (NULL == newnode)//判断空间是否开辟
	{
		perror("malloc fail");
		return NULL;
	}

	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

头插数据

头部插入数据本质是将源头结点的地址,赋给头插的新节点的存放下一个结点地址的指针变量中。然后改变头指针的指向,让头指针指向新的结点。
![在这里插入图片描述](https://img-blog.csdnimg.cn/eb101b4106cf44e4a9a0a6cecdb663bd.png


void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);//防止**pphead空指针

	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

尾插数据

相较于头插数据,尾插数据我们需要先找到链表的尾结点。将插入前的尾结点的下一个结点改成插入结点的地址。然后插入新的结点。需要考虑空链表情况,并且需要注意的是找到最后一个结点的条件是当该结点的下一个指向指针变量的地址为NULL。
在这里插入图片描述

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

	SLTNode* newnode = SLTBuyNode(x);

	if (*pphead == NULL)//空链表直接插入
	{
		*pphead = newnode;
	}
	else
	{
		//链表不为空,找尾结点
		SLTNode* tail = *pphead;

		while (tail->next)//找尾
		{
			tail = tail->next;
		}

		tail->next = newnode;//尾插
	}
}

查找单链表

在介绍单链表某个结点后插入数据前,我们要掌握单链表查找结点这个功能的实现。首先,查找单链表其实不需要二级指针,在前面的两个插入中,在参数部分采用二级指针。是希望用户传参时传一级指针变量的地址。只有传址调用,形参的修改才能够影响实参。当然将修改链表内容的结构部分的参数部分设计成二级指针不是唯一的设计参数的方法。而查找单链表结点,并不需要进行对原单链表修改,故参数部分设计成一级指针。查找功能就是遍历一遍链表,找到指定的结点后,返回这个结点的地址,找不到返回NULL

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	if (phead == NULL)
	{
		return NULL;
	}
	else
	{
		SLTNode* cur = phead;
		while (cur)
		{
			if (cur->data == x)
				return cur;
			cur = cur->next;
		}
		return NULL;
	}
	
}

在pos位置后插入新节点

首先,将pos->next先存起来,避免插入后找不到原来的下一个结点,然后插入结点,将pos的next指针改为新节点的地址,将新节点的next改成原来的pos位置的next指针。
在这里插入图片描述

void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = SLTBuyNode(x);
	SLTNode* cur = pos->next;
	pos->next = newnode;
	newnode->next = cur;
}

单链表修改数据

单链表修改数据的实现类似于查找的思想,。就是遍历整个单链表,直到找到目标结点,并修改目标结点的数据。值得注意的是,这里的修改需要同上面的插入数据一样,还是进行传址调用。


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

	SLTNode* cur = *pphead;

	while (cur)
	{
		if (cur == pos)
		{
			cur->data = x;
			return;
		}

		cur = cur->next;
	}

	printf("该结点不存在,修改失败\n");
}

单链表删除数据

有插入数据自然就有删除数据,下面我将介绍三种经典的单链表删除接口。

头删数据

头删数据的思想就是将第一个结点指向的地址保存一份,将第一个结点的指针变量赋给头指针或哨兵位头结点的指针变量。然后释放我们刚刚保存的指向第一个结点的指针变量,这样就完成了头删。
在这里插入图片描述

void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);//空指针不可传
	assert(*pphead);//空表不可删

	SLTNode* first = *pphead;
	*pphead = first->next;
	free(first);
	first = NULL;
}

尾删数据

尾删数据需要先找到尾结点前的一个接节点,将尾结点前一个结点的指针变量置空,让后释放尾结点即可。需要注意区分单个节点尾删和多个结点尾删的区别。

在这里插入图片描述

void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);//空链表不可删除
	

	if ((*pphead)->next == NULL)
	{
		//单个结点
		free(*pphead);//删除
		*pphead = NULL;
	}
	else
	{
		//多个结点
		SLTNode* tail = *pphead;

		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail->next);//删除
		tail->next = NULL;
	}
}

删除pos位置后数据

删除pos位置后的思想就先保存pos下一个结点的指针变量,即pos->next->next。然后释放pos的下一个结点,将pos的指针变量改成被删除结点的下一个结点的地址。
在这里插入图片描述

void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);//不为单个结点

	SLTNode* next = pos->next->next;
	free(pos->next);
	pos->next = next;

}

单链表打印

前面的增删查改是正餐,打印功能就是一道饭后甜点了。话不多说我就直接上代码了

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;

	while (cur)
	{
		printf("%d->",cur->data);
		cur = cur->next;
	}
	printf("NULL\n");

}

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

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

相关文章

【云原生】持久化存储之NFS

文章目录介绍一、NFS1. 部署nfs1.1 找一台服务器作为nfs服务端1.2 检查:1.3 创建挂载路径1.4 在nfs服务器启动nfs服务2. 所有node节点部署nfs服务3. 测试—部署nginx应用,使用nfs持久网络存储二、 PV和PVC2.1 PV2.2 PVC2.3 实现流程2.4 PV&PVC挂载步…

day61-day62【代码随想录】二刷数组

文章目录前言一、有效三角形的个数【二分法】二、Pow(x, n)(力扣50)方法一方法二三、在 D 天内送达包裹的能力(力扣1011)【二分法】四、制作 m 束花所需的最少天数(力扣1482)【二分法】每日一题&#xff1a…

你真的知道MySQL索引组织数据的形式吗??

MySQL索引背后的数据结构前言MySQLMySQL背后的数据结构B树B树前言 好久不见,困扰了我许久的阴霾终于散去了,但是随之而来的是学校堆积如山的任务考试,这段时间不可否认我的学习效率和学习效果不是很佳,但是我之前就说过学习是需要贯穿程序猿一生的事情,流水不争先,争的是滔滔不…

Python基础 | Miniconda的安装

文章目录什么是Miniconda3Miniconda安装JupyterMiniconda运行JupyterMiniconda安装SpyderMiniconda和Anaconda对比Miniconda安装第三方库什么是Miniconda3 Miniconda是conda的免费的最小安装包。它是Anaconda的小型引导程序版本,仅包含了conda,Python&a…

【架构师】跟我一起学架构——Serverless

博客昵称:架构师Cool 最喜欢的座右铭:一以贯之的努力,不得懈怠的人生。 作者简介:一名Coder,软件设计师/鸿蒙高级工程师认证,在备战高级架构师/系统分析师,欢迎关注小弟! 博主小留言…

个人收集的网站,可以参考(程序员可收藏)

程序员是一个需要不断学习的职业,幸运的是,在这个互联网时代,有很多渠道可以获取知识。 1在线教程 1、how2j.cn 地 址:https://how2j.cn/ 简 介:一个Java全栈开发教程网站,内容全面,简洁…

Docker Desktop安装本地Kubernetes集群

目录 下载安装说明 下载Docker Desktop windows需要开启Hyper-v 启用kubernetes kubectl配置 设置path环境变量 验证安装是否成功 实现Nginx容器的部署 按顺序进行nginx创建 Nginx的相关信息 Setup local Kubernetes cluster with Docker Desktop - DEV Community 上面…

UNIX网络编程-卷1_TCP粘包问题解决方法

这篇文件记录流协议粘包问题。首先记录什么是粘包,其次介绍粘包产生的原因,最后给出粘包的解决方法。 1 流协议与粘包 第一种情况:主机B一次读一个M消息 ,不会产生粘包; 第二种情况:主机B一次读M1M2个消息…

数据模型(下):反规范化和维度模型

接前文: 数据模型(上)_专治八阿哥的孟老师的博客-CSDN博客 数据模型(中):键和规范化_专治八阿哥的孟老师的博客-CSDN博客 5.反规范化 反规范化是选择性地违反规范化规则并在模型中重新引入冗余的过程,额外的冗余有助于降低数据检索的时间,且创建一个用户友好的模型。 数…

一文吃透 Spring 中的IOC和DI

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

【Redis应用】查询缓存相关问题解决(二)

🚗Redis应用学习第二站~ 🚩起始站:【Redis应用】基于Redis实现共享session登录(一) 🚩本文已收录至专栏:Redis技术学习 👍希望您能有所收获,底部附有完整思维导图 一.概述 本篇我们会一起来学习…

项目管理工具DHTMLX Gantt灯箱元素配置教程:只读模式

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的大部分开发需求,具备完善的甘特图图表库,功能强大,价格便宜,提供丰富而灵活的JavaScript API接口,与各种服务器端技术&am…

【深度探讨】公共部门在选择区块链平台时要考虑的6个方面

发表时间:2022年8月17日 信息来源:bsvblockchain.org 与私营企业相比,全球的公共部门组织在考虑升级软件解决方案时面临着一系列的全新挑战。公共部门的决策流程冗长而复杂,他们要不惜一切代价避免对现有业务造成干扰,…

ISP全流程简介

ISP的pipline总结 ISP(Image Signal Processor),即图像处理,主要作用是对前端图像传感器输出的信号做后期处理,主要功能有线性纠正、噪声去除、坏点去除、内插、白平衡、自动曝光控制等,依赖于ISP才能在不同的光学条件下都能较好…

面试 - 软件工程体系

今天是我人生中的第二次面试,第一次面试到技术问题。 面试公司:无锡信捷电气股份有限公司 面试时间:2023 年 3 月 6 日 15:30 面试地点:西安工程大学(临潼校区)D-188 在技术面中,我表现的不是很…

外骨骼机器人(五):步态分析之正常步态

研究病理步态之前,需要了解正常步态,作为判断标准。但是需要记住两个问题:1.“正常”因人而异,性别、年龄、身体情况都需要考虑在内,因此,需要对不同的个体选择合适的正常标准;2.即使病人的步态与正常步态有某种不同,这也不能说明这是不可取的,也不能说明应该把它变成…

计算机网络【王道】

文章目录第一章 计算机网络体系结构计算机网络概述计算机网络的概念计算机网络的组成计算机网络的功能计算机网络的分类计算机网络的性能指标计算机网络体系结构与参考模型计算机网络分层结构计算机网络协议、接口、服务的概念ISO/OSI 参考模型和 TCP/IP模型第二章物理层基本概…

Codeforces Round 855 (Div. 3) A-E2

比赛链接:Dashboard - Codeforces Round 855 (Div. 3) - Codeforces A:模拟 题意:给定一个字符串,问这个字符串是不是猫叫。定义是猫叫得字符串: 1:必须由大写或小写得M(m),E&…

【大数据是什么】

大数据是什么大数据是做什么的?大数据主要有哪些职位 ?大数据运维工程师数据仓库开发工程师ETL工程师大数据开发工程师BI工程师算法工程师大数据平台开发工程师大数据架构师讲述一下自己的大数据学习之路大数据是做什么的? 2014年&#xff0c…