DS线性表之单链表的讲解和实现(2)

news2025/1/12 16:18:20

文章目录

  • 前言
  • 一、链表的概念
  • 二、链表的分类
  • 三、链表的结构
  • 四、前置知识准备
  • 五、单链表的模拟实现
    • 定义头节点
    • 初始化单链表
    • 销毁单链表
    • 打印单链表
    • 申请节点
    • 头插数据
    • 尾插数据
    • 头删数据
    • 尾删数据
    • 查询数据
    • 在pos位置之后插入数据
    • 删除pos位置之后的数据
  • 总结


前言

  本篇的单链表完全来说是单向不带头单链表,这种和另外一种链表(双向带头循环链表)使用最广泛,我们只要对它们两个有所了解即可

  正文开始!


一、链表的概念

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

二、链表的分类

在这里插入图片描述

三、链表的结构

  就如同下图一样,一节一节,前面连着后面就是链表的一种表现
在这里插入图片描述
在这里插入图片描述
同时我们也发现以下几点:

  1. 从上图可看出,链式结构在逻辑上是连续的,但是在物理上不一定连续
  2. 节点一般都是在上申请出来的
  3. 从堆上申请空间,两次申请得到的内存可能连续,也可能不连续

物理结构:数据实际存储在内存中的结构;
逻辑结构:想象出来的结构

四、前置知识准备

在正式开始实现之前,我希望你有以下认识:

  1. 实现部分接口需要通过二级指针接受实参:原因在于我们需要可以修改实参(而形参只是实参的一份拷贝,要想修改实参,必须得传指针,同样若实参本来就是指针,那么就要传指针的指针,即二级指针),而是实参为一级指针时(同样是传递地址),需要使用二级指针进行接受,否则获得临时拷贝,不会影响到实参。修改实参的情况,比如一开始为空,在插入时需将头指针存储在有效结点的的地址上,需要改变实参的值
  2. 单链表的初始化:这里实现链表,没有必要进行初始化,初始化对于一开始就要开辟的空间有初始化的需求,表示多个节点通过地址链接在一起,那么只需要开辟新节点的时候,初始化下就行了(有哨兵位需要初始化)
  3. 二级指针断言:二级指针存放的是头节点的地址,头节点的地址为空,那么还有什么意义呢?

五、单链表的模拟实现

定义头节点

//单链表节点
//根据定义需要存储一个数据和一个指向下一个结点的指针
typedef int SLDataType;//定义数据类型,可以根据需要更改,typedef一下就很方便
typedef struct SList
{
	SLDataType data;    //数据域 存储数据
	struct SList* next; //指针域 存储指向下一个结点的指针
}SList;

请注意,这里不能在节点内就单独用SList来定义next指针,因为这时候还没有typedef成功呢,还在节点内部

初始化单链表

因为创建一个变量实质是给变量开辟一块内存空间,但是这块内存空间可能有遗留的数据,所以在创建变量之后需要进行初始化,而数据域我们也不清楚到底该传那个,随便传个0就行,但是指针域就必须置空了,否则就是野指针

void SListInit(SList* phead)
{
	assert(phead);     //防止传入空指针,传入则报错
	phead->data = 0;   //将数据初始化为0
	phead->next = NULL;//将结点指针初始化为NULL
}

销毁单链表

有开辟内存,自然而然的就有还回内存,即销毁单链表

在这里插入图片描述

void SListDestroy(SList* phead)
{
	assert(phead);
	SList* cur = phead; //为了能在后序找到头结点,所以新创建一个变量指向头结点
	while (cur != NULL)
	{
		SList* next = cur->next;
		free(cur);
		cur = next;
	}
}

我们不妨来想想为什么是传一级指针即可,首先,我们这里是为了销毁内存,虽然说形参的这个节点指针和实参的节点指针地址不一样,但是所存的节点都是同一个节点!,所以可以直接传指针,有因为我们说链表在物理上是不连续的,所以得通过指针跳着跳着一个个销毁

打印单链表

在这里插入图片描述
同样的,我们只要传一级指针就可以了,且通过指针来跳转

void SListPrint(SList* phead)
{
	assert(phead);
	SList* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

申请节点

在插入中使用相当频繁,所以我们再对此单独实现一个函数,使得代码更加的结构化
在这里插入图片描述
请注意,指针并不单独开空间,它起到的更多是一个中间人的作用,通过指针来控制

SList* BuySeqList(SLDataType x)
{
	SList* pnewNode = (SList*)malloc(sizeof(SList));//动态开辟一个单链表类型大小
	if (pnewNode == NULL)//动态开辟的内存不一定成功,所以需要判断
	{
		printf("malloc fail\n");
		exit(-1);
	}
	
	//内存开辟成功则把数据赋值到指定位置
	pnewNode->data = x;
	pnewNode->next = NULL;

	return newnode;
}

头插数据

在这里插入图片描述

void SListPushFront(SList** pphead, SLDataType x)
{
	SList* newnode = BuySeqList(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

尾插数据

在这里插入图片描述

void SListPushBack(SList** pphead, SLDataType x)
{
	SList* newnode = BuySeqList(x);
	if (*pphead == NULL) // 没有节点的时候
	{
		*pphead = newnode;
	}
	else // 有节点的时候
	{
		SList* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

头删数据

void SListPopFront(SList** pphead)
{
	assert(*pphead);//头结点不为空则有数据
	SList* head = (*pphead)->next;
	free(*pphead);
	*pphead = head;
}

在这里插入图片描述

尾删数据

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

在这里插入图片描述

查询数据

找到则返回当前当前数据结点地址,没找到则返回空地址
在这里插入图片描述

SList* SListFind(SList* phead, SLDataType x)
{
	assert(phead);
	SList* cur = phead;
	while (cur != NULL)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

在pos位置之后插入数据

在这里插入图片描述

void SListInsertAfter(SList* pos, SLDataType x)
{
	assert(pos);
	SList* newnode = BuySeqList(x);
	SList* next = pos->next;
	pos->next = newnode;
	newnode->next = next;
}

删除pos位置之后的数据

在这里插入图片描述

void SListEraseAfter(SList* pos)
{
	assert(pos);
	assert(pos->next);//判断pos之后是否有数据,没数据则报错
	SList* next = pos->next->next;
	free(pos->next);
	pos->next = next;
}

总结

  链表可以说是CS学生遇到的第二个劝退点了(第一个是指针),它是我们所学知识的一个集成展现,需要我们对前面知识的充分掌握,所以对计算机来说,知识比较连贯,这也是学习它比较难受的地方

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

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

相关文章

使用PyTorch从0实现Fashion-MNIST数据集分类

完整代码: from d2l import torch as d2l import torch from torchvision import transforms from torchvision import datasets from torch.utils.data import DataLoader import matplotlib.pyplot as plt from IPython import displaydef get_fashion_mnist_la…

BBR 的不公平性

BBR 公平收敛在相图中的细节 和 aimd,bbr,inflt 守恒的收敛相图总结 已经介绍了 BBR 的 gain 不公平性,本文介绍 BBR 的 RTT 不公平性。 直觉上,BBR 采用 probe_quota gain * maxbw * minrtt 来 probe 带宽,minrtt 越…

掌握Postman,开启API测试新纪元!

Postman是一款流行的API测试工具和开发环境,旨在简化API开发过程、测试和文档编制。它提供了一套功能强大的工具,帮助开发人员更轻松地构建、测试和调试Web服务。 Postman 工具的优势 Postman 可以快速构建请求、还可以保存以后再使用。 Postman 还提…

改进系列:TransUnet结合SAM box改进对MICCAI FLARE腹部13器官图像分割

目录 1、前言 2、实现思路 3、实验代码 3.1 环境配置 3.2 数据集 3.3 训练 3.4 指标 3.5 推理 4、其他 1、前言 本章尝试将TransUnet和SAM结合,以期望达到更换的模型 TransUnet作为医学图像分割的基准,在许多数据集上均取得了很好的效果&#x…

JavaSE——认识异常

1.概念 在生活中,人有时会生病,在程序中也是一样,程序猿是一帮办事严谨、追求完美的高科技人才。在日常开发中,绞尽脑汁将代码写的尽善尽美,在程序运行过程中,难免会出现一些奇奇怪怪的问题。有时通过代码很…

2024/10/12 计组大题专训

2018: 2019: 2020: 2021:

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表(重点掌握)】 可以使用类:“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁,就是直接给put,get等方法加上synch…

AI+若依框架day02

项目实战 项目介绍 帝可得是什么 角色和功能 页面原型 库表设计 初始AI AIGC 提示工程 Prompt的组成 Prompt练习 项目搭建 点位管理 需求说明 库表设计

多线程学习篇四:synchronized

1. synchronized 的使用 1.1 作用于实例方法 Slf4j(topic "c.Test01") public class Test01 {public synchronized void method1() {// 代码逻辑} } 等价于下列写法: Slf4j(topic "c.Test01") public class Test01 {public void method1…

基于机器学习的虚假新闻智能检测系统

温馨提示:文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 随着互联网的普及和社交媒体的发展,虚假新闻(fake news)问题日益严重,对社会和个人产生了诸多负面影响。传统的新闻审核方法通常依赖于人工审核&…

基于gewechat制作第一个微信聊天机器人

Gewe 个微框架 GeWe(个微框架)是一个创新性的软件开发框架,为个人微信号以及企业信息安全提供了强大的功能和保障。GeWe的设计旨在简化开发过程,使开发者能够高效、灵活地构建和定制通信协议,以满足不同应用场景的需求…

SSL---SSL certificate problem

0 Preface/Foreword 0.1 SSL certificate problem 开发过程中,gitlab-runner连接gitlab时候出现SSL 证书问题。 场景:公司的gitlab runner服务器引入了SSL证书,每年都会主动更新一次。当前的gitlab-runner运行在PC机器上,但是g…

ZYNQ使用XGPIO驱动外设模块(前半部分)

目录 目录 一、新建BD文档,添加ZYNQ处理器 1.BD文档: 2.在Vivado中,BD文件的生成过程通常包括以下步骤: 1)什么是Tcl Console: 3.PL部分是FPGA可编程逻辑部分,它提供了丰富的IO资源,可以用于实现各种硬件接口和功…

刘文超数量关系笔记

第一章解题技巧 第一节代入排除法 代入排除是数量关系第一大法。 代入排除顾名思义是将答案选项代入原题目,与题意不符的选项即可排除, 最终得出正确答案。 优先使用代入排除的题型: (1)多位数问题、余数问题、年龄…

node.js服务器基础

node.js的事件循环 node.js是基于事件驱动的,通常在代码中注册想要等待的事件,设定好回调函数,当事件触发的时候就会调用回调函数。如果node.js没有要处理的事件了,那整个就结束了;事件里面可以继续插入事件,如果有事…

【2021】知识图谱导论(陈华钧)——阅读思考与笔记

tips:其中所有【】表示的内容为博主本人想法,非作者观点,请注意辨别。 这是一本全面覆盖知识图谱多个方面的书籍。书中不仅详细介绍了知识图谱的表示、存储、获取、推理、融合、问答和分析等七大方面,还深入探讨了多模态知识图谱…

【Nginx系列】Nginx启动失败

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

[⑦5G NR]: PSS/SSS同步信号学习

在5G中,PSS(Primary Synchronization Signal) 主同步信号和SSS(Secondary Synchronization Signal)辅同步信号是用于物理层的信号,用于小区的搜索。 PSS 跟据协议38.211 7.4.2.2章节,PSS是3条长度为127的m序列,分别对应 N I D (…

空间解析几何4-空间中线段到圆的距离【附MATLAB代码】

目录 理论公式 matlab代码 理论公式 对于解一元4次方程,请详见我的博客 一元四次方程求解 -【附MATLAB代码】-CSDN博客文章浏览阅读1.4k次,点赞41次,收藏4次。最近在研究机器人的干涉(碰撞)检测,遇到了一…

义堂镇韦家巷村第十六届老人节暨孝善互助基金启动仪式成功举行

金秋十月爽,浓浓敬老情。10月11日晚,以“孝善韦家巷情暖重阳节”为主题的兰山区义堂镇韦家巷村第十六届老人节暨韦家巷村孝善互助基金启动仪式在韦家巷村文化广场盛大举行。 山东省民间文艺家协会副主席、临沂市民间文艺家协会主席、临沂市文联办公室主…