当前位置: 首页 > 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…...

记录面试问题

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

(六十四)设计索引的时候,我们一般要考虑哪些因素呢?(上)

本周我们将要讲解一下设计索引的时候,我们通常应该考虑哪些因素,给哪些字段建立索引,如何建立索引,建立好索引之后应该如何使用才是最合适的。 可能有的朋友会希望尽快更新后面的内容,但是因为工作的原因的确非常忙&a…...

【蓝桥杯嵌入式】LCD屏的原理图解析与代码实现(第十三届省赛为例)——STM32

🎊【蓝桥杯嵌入式】专题正在持续更新中,原理图解析✨,各模块分析✨以及历年真题讲解✨都在这儿哦,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 - 蓝…...

论文学习——Reproducing Activation Function for Deep Learning

论文学习——Reproducing Activation Function Abstract RAFs将集中基础激活函数进行线性组合,构建出神经元级的、数据驱动的激活函数。使用RAFs为激活函数的神经网络可以重现传统的近似工具,也能相对于传统网络以更少的参数量拟合目标函数。训练过程中,RAFs可以以更好的条…...

【趣味学Python】Python基础语法讲解

目录 编码 标识符 python保留字 注释 实例(Python 3.0) 实例(Python 3.0) 行与缩进 实例(Python 3.0) 实例 多行语句 数字(Number)类型 字符串(String) 实例(Python 3.0) 空行 等待用户输入 实例(Python 3.0) 同一行显示多条语句 实例(Python 3.0) 多个语句构…...

虚拟局域网VLAN的实现机制

虚拟局域网VLAN的实现机制1.IEEE 802.1Q帧2.交换的端口类型AccessTrunkHybrid(华为特有)1.IEEE 802.1Q帧 IEEE802.1Q帧(也称Dot One Q帧)对以太网的MAC帧格式进行了扩展,插入了4字节的VLAN标记。 2.交换的端口类型 A…...

Mask R-CNN 算法学习总结

Mask R-CNN 相关知识点整体框架1.Resnet 深度残差学习1.1 目的1.2 深度学习深度增加带来的问题1.3 Resnet实现思想【添加恒等映射】2.线性插值2.1 目的2.2 线性插值原理2.3 为什么使用线性插值?3.FPN 特征金字塔3.1 FPN介绍3.2 为什么使用FPN?3.3 自下而上层【提取特征】3.4 …...

Gorm -- 添加记录

文章目录添加单条记录直接添加模型对象赋予默认值方法一: gorm 标签赋予默认值方法二: 设置钩子方法(Hooks)指定字段插入插入时忽略某些字段插入时禁止使用钩子方法添加多条记录通过对象列表插入通过字典列表插入在字典中使用SQL内…...

go提高升阶(四) I/O流学习

I/O 官网课程 购买课程找博主推荐 文章目录I/O文件信息创建文件、目录IO读IO写(权限)文件复制Seeker接口断点续传遍历文件夹bufio电脑中一切,都是以 二进制流的形式存在的。jpg:010100000010010101001010101010010101010 编码格式,还原为一个…...

【代码随想录训练营】【Day28】第七章|回溯算法|93.复原IP地址|78.子集|90.子集II

复原IP地址 题目详细:LeetCode.93 这道题与上一道练习题分割回文字符串十分详细,一样是涉及到分割字符串、判断字符串、递归与回溯的问题,所以这道题要解决的难点在于: 如何分割IP地址字符串如何判断分割的IP地址是否合法递归的…...

Get请求和Post请求区别

前后端交互请求数据的方式有很多种。 例如:Get Post Put Patch Delete Copy 等等很多请求方式 但是用的最多的就是Get和Post Get请求方式 1. get多用于从服务器请求获取数据 2.get传送的数据量较小,不能大于2KB 3.get安全性非常低 Post请求方式 1.…...

wordpress 5.2.2/百度官方网址

文章目录1、什么是弱网测试2、弱网环境的影响3、弱网环境测试场景4、使用Fiddler进行弱网测试(1)Fiddler模拟弱网环境(2)设置弱网的参数(3)进行弱网测试对比(4)恢复设置5、补充&…...

wordpress 视频压缩/深圳seo公司助力网络营销飞跃

0引言 课程设计是本科阶段大学生应用实践课程的重要组成部分,课程设计报告是对课程设计的结果进行整理、总结,是课程设计的重要组成部分。认真编写则会加深对所学知识的体会和理解,否则是纯粹的在浪费资源。为了让大家编写好课程设计报告&am…...

nginx wordpress 404/网络营销课程实训总结

我们已经学习了字符串和数字基础的处理方法和逻辑,大家有没有觉得使用起来很方便,编程的过程中也是很给力的呀!其实Python还有更多字符串处理的方法,大家今天就一起来体验一下吧小朋友们可以先复习一下前一节课的知识哈&#xff0…...

wordpress整站安装/十大免费推广平台

摘要:图灵图灵细胞序列改变跳跃中能自身基因位置的一段D称为。转录模板基因一条链为A的是以,够模互补合成过程配对碱基原则按照A的。小的序列或者通过者完配对与靶抑制引起全地编码部分靶m的R地或A的、拟计难非分子翻译可以。...图灵图灵细胞序列改变跳跃…...

成都网站建设报价/seo实战培训课程

题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条…...

做网站教学书/推广平台怎么找客源

Tomcat对于J2EE或Java web开发者而言绝不陌生,但说到Realm,可能有些人不太清楚甚至没有听说过,那么到底什么是Realm?简单一句话就是:Realm是Tomcat中为web应用程序提供访问认证和角色管理的机制。配置了Realm&#xff…...