当前位置: 首页 > news >正文

什么是链表,如何实现?(单链表篇)

欢迎来到 Claffic 的博客 💞💞💞

      “仅仅活着是不够的,还需要有阳光,自由和花的芬芳。”

前言:

在日常使用的网站和软件中,列表属于最常见的一种东西了,其实现形式有顺序表,链表等,主要功能有增删查改,那么链表具体是什么,如何实现?这篇博客为你解答。

注:

这篇博客属于数据结构内容,建议学习完C语言的小伙伴食用~


目录

🥰Part1: 何为链表

1.链表的概念

2.链表的结构 

💗Part2: 链表的实现

1.开工准备 

1.1创建项目

1.2建立结点

1.3动态申请结点

2.相关功能实现

2.1打印链表

2.2尾部插入

2.3头部插入

2.4尾部删除

2.5头部删除

2.6查找位置

2.7在pos位置之后插入

2.8删除pos之后的值

2.9pos之前插入

2.10删除pos结点


Part1: 何为链表

1.链表的概念

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

简单理解下这个概念,就是一个存储单元中有 存储的数据 下一个存储单元的地址 ,经过这个存储单元可利用地址找到下一个存储单元。

下面讲到结构就会更加明白: 

2.链表的结构 

一个简单链表的逻辑图 

注意:

• 链式结构在逻辑上连续,在物理上不一定连续(存储的地址不连续);

• 现实中的结点一般是从上申请出来的;

• 从堆上申请的空间,按照一定策略分配,两次申请的空间不一定连续。 

Part2: 链表的实现

1.开工准备 

1.1创建项目

按照惯例,在 Single linked list 解决方案中创建三个项:

SList.h:头文件,声明所有函数;

SList.c:源文件,实现各函数;

test.c:  源文件,主函数所在项,可调用各函数。

1.2建立结点

这里创建一个结点的结构体,包含要储存的数据和下一个结点的地址:

typedef int SLTDateType;
typedef struct SListNode
{SLTDateType data;struct SListNode* next;//指向结构体的指针,可通过它找到下一个结构体
}SLTNode;//将此结点简易命名,方便引用

1.3动态申请结点

关于为什么要动态申请:

动态申请按需分配内存,既不会空间多余,也不会浪费

SLTNode* BuySListNode(SLTDateType x)
{//动态申请SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc failed");return;}//初始化newnode->data = x;newnode->next = NULL;return newnode;
}

注意动态申请后要进行判断和初始化。

2.相关功能实现

2.1打印链表

我们打印的是一个结点中的数据

void SListPrint(SLTNode* phead)
{SLTNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;//地址不一定连续,不可++;}printf("NULL\n");
}

这里值得注意的是 遍历过程中是如何前进的:
 

因为地址不一定连续,所以要进行赋值,不可直接++,这一点很重要 

2.2尾部插入

尾部插入,在申请一个新的结点后,要做的最重要的一点就是 末端节点 中的 结构体指针 要指向   新的结点 

尾部插入有两种情况:

• phead 为NULL;

• phead 不为NULL。

我们一个个分析:

第一种情况 比较简单,phead 为空

要让 phead 指向 newnode 指向的结点 ,直接赋值即可

*pphead = newnode;//pphead 是指向 phead 的指针,后面会讲利用二级指针的原因

第二种情况 就比较复杂,

因为要实现上下的链接

再寻找一个 tail 用来遍历整个链表,遇到 NULL 时停止。

void SListPushBack(SLTNode** pphead, SLTDateType x)
{assert(pphead);SLTNode* newnode = BuySListNode(x);if (*pphead == NULL){*pphead = newnode;}else{//查找尾部SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;//改变的是结构体成员,用结构体的指针当然可以}
}

需要注意的是

形参的改变不影响实参,需要通过二级指针来改变 phead.

如要改变 int* ,就需要通过 int** 来改变。

2.3头部插入

头部插入,包括前后两个方向的链接:一是 phead 要指向新的结点 ,二是 新结点中的结构体指针 指向原链表的第一个结点 

我是图示 

void SListPushFront(SLTNode** pphead, SLTDateType x)
{assert(pphead);SLTNode* newnode = BuySListNode(x);newnode->next = *pphead;*pphead = newnode;
}

2.4尾部删除

我的思路是找到倒数第二个结点,但还有只有一个结点的情况。

只有一个结点时,不用查找,直接释放并置空该节点;

有多个结点时,先找到倒数第二个结点,将该节点的下一个结点释放并置空即可。

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

2.5头部删除

要头部删除,令 phead 指向第二个结点后释放第一个结点即可。

void SListPopFront(SLTNode** pphead)
{assert(pphead);SLTNode* first = *pphead;*pphead = first->next;free(first);first = NULL;
}

2.6查找位置

查找特定数值所在的位置,思路是通过头指针遍历,最多遍历一遍链表

SLTNode* SListFind(SLTNode* plist, SLTDataType x)
{SLTNode* cur = plist;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return cur;
}

最后返回的是 结构体指针 ,也就是数值所在结构体的地址。 

2.7在pos位置之后插入

 在创建 newnode 之后,改变指针指向即可

我是图示  

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

注意:要先改变 newnode.next 的值,再改变 pos.next 的值,否则会被覆盖。

2.8删除pos之后的值

可以先找到要删除的结点,也就是pos的下一个结点,再将该节点释放置空 

我是图示  

void SListEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* del = pos->next;pos = del->next;free(del);del = NULL;
}

2.9pos之前插入

如果pos指向第一个结点,就相当于前插

其他情况下,需要找到pos的前一个,再进行修改。 

我是图示  

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);if (pos == *pphead){SListPushFront(pphead, x);}else{//查找pos前一个SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuySListNode(x);prev->next = newnode;newnode->next = pos;}
}

2.10删除pos结点

寻找pos的前一个,修改其指向,pos释放置空即可

我是图示  

void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(*pphead);assert(pos);//查找pos前一个SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;
}

代码已上传至我的 gitee 

拿走不谢~


 

总结:

这篇博客介绍了最简单的链表 -- 单链表的概念和结构,并进行了相关功能的实现,第一次接触可能会难很消化,建议充分理解结构后进行实现呐~ 

码文不易 

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

相关文章:

什么是链表,如何实现?(单链表篇)

欢迎来到 Claffic 的博客 💞💞💞 “仅仅活着是不够的,还需要有阳光,自由和花的芬芳。” 前言: 在日常使用的网站和软件中,列表属于最常见的一种东西了,其实现形式有顺序表&#xff0…...

探针台简介

探针台,是我们半导体实验室电学性能测试的常用设备,也是各大实验室以及芯片设计、封装测试的熟客。设备具备各项优势,高性能低成本,用途广,操作方便,在不同测试环境下,测试结果稳定,…...

ABAP 辨析 标准表|排序表|哈希表

1、文档介绍 本文档将介绍内表的区别和用法,涉及标准表、排序表、哈希表 2、用法与区别 2.1、内表种类 内表顶层为任意表,任意表分为索引表和哈希表,索引表又可分为标准表和排序表,结构如图: 2.2、内表用法 2.2.1…...

MIGO 物料过账 创建物料凭证 BAPI_GOODSMVT_CREATE

文章目录1.前台操作2.需求分析2.1调用方式2.2分为两大概括:2.3业务逻辑细节图3.BAPI_GOODSMVT_CREATE4.RFC接口代码5.总结1.前台操作 SAP CO01(创建生产订单)/MIGO(发货投料)前台操作 这里面有migo的前台操作,首先了解前台操作后再去写RFC接口是比较容易理解的.!! 2.需求分析…...

项目经理处理团队冲突 5大注意事项

1、在时间、场景、体验矩阵中的5种处理方式 第一种方式:强迫命令,即职位高的一方在不考虑对方感受的情况下,强迫职位低的一方接受自己的意见。这种处理方式的适用场景为重要且紧急,这种方式团队成员的体验感低。 第二种方式&#…...

Linux(Centos)安装TDengine

目录1:简介2:前期准备3:安装4:启动5:开机自启动6:安装客户端驱动(如果别的服务器需要链接TD则需要此步操作)7:基础命令1:简介 官网: https://www.taosdata.com/简介&…...

大数据处理技术导论(6) | Datawhale组队学习46期

文章目录1. hive 概述2. hive 与传统关系型数据库的对比3. hive 数据类型4. hive 数据模型5. hive 实战5.1 创建表5.2 修改表5.3 清空表、删除表5.4 其他命令项目地址 https://github.com/datawhalechina/juicy-bigdata,感谢项目团队的付出。本次主要学习 hive 相关…...

Java——异常

目录 什么是异常 异常处理主要的5个关键字 异常的体系结构 异常语法 异常的分类 异常的处理流程 异常的处理 防御式编程 异常的抛出 throw的注意事项 异常的捕获 异常声明throws try-catch捕获处理 finally 自定义异常类 throw和throws区别 什么是异常 程序在运行时出现错…...

Netty之io.netty.util.concurrent.Promise与io.netty.util.concurrent.Future初解

目录 目标 Netty版本 Netty官方API 三者之间的关系 基本使用方法 java.util.concurrent.Future io.netty.util.concurrent.Future io.netty.util.concurrent.Promise 目标 了解io.netty.util.concurrent.Promise与io.netty.util.concurrent.Future的基本使用方法。了解…...

【正点原子FPGA连载】第二十一章AXI DMA环路测试 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第二十一章AXI D…...

手把手搭建springboot项目06-springboot整合RabbitMQ及其原理和应用场景

目录前言工作流程-灵魂画手名词解释交换机类型一、安装1.1 [RabbitMQ官网安装](https://www.rabbitmq.com/download.html)1.2 Docker安装并启动二、食用教程2.1.导入依赖2.2 添加配置2.3 代码实现2.3.1 直连(Direct)类型2.3.2 引入消息手动确认机制2.3.2…...

如何根据IP地址判断是IPv4还是IPv6

IPv4地址的书写形式为:“192.168.0.1” IPv6地址的书写形式为:“2001:DB8:85A3:8D3:1319:8A2E:370:7344” 给你一个IP地址,它有三种可能:IPv4、IPv6、既不是IPv4也不是IPv6的无效地址。所以,如果用函数ipGetAddressAsNumber,只能判断是不是ipv4,编写如下函数: int R…...

山地车和公路车怎么选

公路车: 只能适应平坦的路面,骑行阻力小,速度快比较适合新手 山地车: 能适应所有路面,更注重操控性和舒适性 怎么选? 1、先决定用途 旅游:旅行车、山地车、 通勤:公路车 2、预…...

Zotero设置毕业论文/中文期刊参考文献格式

大家在使用zotero时很容易遇到的问题: 英文参考文献中有多个作者时出现“等”,而不是用"et al"引文最后面有不需要的DOI号,或者论文链接对于一些期刊分类上会出现OL字样,即[J/OL]作者名为全大写 本文主要解决以上几个…...

【人工智能与深度学习】自动编码器的简介

【人工智能与深度学习】自动编码器的简介 自动编码器的应用图片生成像素空间和潜在空间插值的差异图像超级分辨率图像修补由文字说明转成图片什么是自动编码器?为什么我们用自动编码器?重建损失完成过度降噪自动编码器:Denoising autoencoder压缩式自动编码器定义自动编码器…...

Isaac-gym(9):项目更新、benchmarks框架梳理

一、项目更新 近期重新git clone isaac gym的强化部分(具体见系列第5篇)时发现官方的github库有跟新,git clone下来后发现多了若干个task,在环境配置上也有一定区别。 例如新旧两版工程项目的setup.py区别如下: git …...

Linux 学习笔记(一):终端 和 Shell 的区别和联系

一、Linux 介绍 1、什么是 Linux Linux 就是一个操作系统,全称 GNU/Linux,是一种类 Unix 操作系统Linux 一开始是没有图形界面的,所有操作都靠 命令 完成。如 磁盘操作、文件存取、目录操作、进程管理、文件权限 等等,可以说 Li…...

cycleGAN算法解读

本文参考:https://blog.csdn.net/Mr_health/article/details/112545671 1 CycleGAN概述 CycleGAN:循环生成对抗神经网络,是一种非监督学习模型。 Pix2pix方法适用于成对数据的风格迁移,而大多数情况下对于A风格的图像&#xf…...

解读“方差”

其实,从这个标题就可以看出来,方差,这个问题不简单, 先给出定义: 方差其实应该叫,差方差,(差方)差,差的平方的差,与差的平方之间的误差&#xff0…...

记录面试问题

以下问题不分先后,按照印象深浅排序,可能一次记录不完成,后面想起来会及时补充,如有不对,恳请各位围观大佬多多指教🙏 印象最深的是一道很简单很简单的题目,我结束面试之后赶紧代码敲敲发现答错…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

MMaDA: Multimodal Large Diffusion Language Models

CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...