单链表原来是这样实现的!
文章目录
- 前言
- 1. 链表的概念及结构
- 1.1在链表里,每节“车厢”是什么样的呢?
- 1.2为什么还需要指针变量来保存下⼀个节点的位置?
- 2. 单链表的实现
- 1. 定义结构体`(Seqlist)`
- 2. 打印函数`(SLTPrint)`
- 小插曲,创建节点函数`CreateNode`
- 3. 尾插函数 `(SLTPushBack)`
- 4. 头插函数 `(SLTPushFront)`
- 5. 尾删函数(`SLTPopBack`)
- 6. 头删函数(`SLTPopFront`)
- 小插曲,pos查找函数` SLTFind`
- 7. “插入指定位置前”函数(`SLTInster`)
- 8.“删除指定位置后”函数
- 9.销毁单链表函数`SLTDestroy`
- 结语
前言
“我会定期分享我的学习经验,也欢迎大家留言和交流,让我们共同学习和进步!感谢大家的支持,让我们一起开启这段充满技术乐趣的旅程吧!”
1. 链表的概念及结构
概念:链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的

链表的结构跟火车车厢厢相似,淡季时车次的车厢会相应减少,旺季时车次的车厢会额外增加几节。只需要将火车里的某节节厢去掉/加上,不会影响其他车厢,每节车厢都是独立存在的。
车厢是独里存在的,且每节车厢都有车门。想象⼀下这样的场景,假设每节车厢的车门都是锁上的状态,需要不同的钥匙才能解锁,每次只能携带⼀把钥匙的情况下如何从车头走到车尾?
最简单的做法:每节车厢里都放⼀把下一节车厢的钥匙。
1.1在链表里,每节“车厢”是什么样的呢?

与顺序表不同的是,链表⾥的每节"车厢"都是独立申请下来的空间,我们称之为“结点/节点”,节点的组成主要有两个部分:当前节点要保存的数据和保存下一个节点的地址(指针变量)。
图中指针变量 plist保存的是第⼀个节点的地址,我们称plist此时“指向”第⼀个节点,如果我们希望plist“指向”第⼆个节点时,只需要修改plist保存的内容为0x0012FFA0。
1.2为什么还需要指针变量来保存下⼀个节点的位置?
链表中每个节点都是独立申请的(即需要插⼊数据时才去申请⼀块节点的空间),我们需要通过指针
变量来保存下⼀个节点位置才能从当前节点找到下⼀个节点。
2. 单链表的实现
1. 定义结构体(Seqlist)
在SList.h头文件中
typedef int SLNDataType;
typedef struct SListNode
{SLNDataType val;struct SList* next;//这里只是指针,不是结构体
}SLNode;
2. 打印函数(SLTPrint)
注意下述代码皆是:
在SList.h头文件中定义函数
在SList.c文件中实现函数
在Test.c文件中函数测试
SeqList.h文件中
定义函数:

SList.c文件中
实现函数:
void SLTPrint(SLNode* phead) //打印单链表
{SLNode* cur = phead;while (cur != NULL){printf("%d->", cur->val);cur=cur->next;}printf("NULL");
}
小插曲,创建节点函数CreateNode
在实现下面的插入函数之前,还需要一个函数来开辟空间给新的节。
函数实现
SLNode* CreateNode(SLNDataType x) //新建节点,开辟空间
{SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));if (newnode == NULL){perror("malloc fail");exit(-1);}newnode->val = x;newnode->next = NULL;return newnode;
}
3. 尾插函数 (SLTPushBack)
定义函数:

实现函数:
void SLTPushBack(SLNode** pphead, SLNDataType x) //尾插
{SLNode* newnode = CreateNode(x);if (* pphead == NULL){*pphead = newnode;}else{SLNode* tail = * pphead; //找尾while (tail->next != NULL){tail = tail->next; //因为tail是局部变量,而tail->next是结构体,出来作用域tail就销毁了}tail->next = newnode; //所以这里把newnode赋值给tail->next}
}
函数测试:
int main()
{SLNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPrint(plist);return 0;
}
运行结果:

4. 头插函数 (SLTPushFront)
定义函数:

实现函数:
void SLTPushFront(SLNode** pphead, SLNDataType x) //头插
{ SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));newnode->next =* pphead;newnode->val = x;*pphead = newnode;
}
函数测试:
int main()
{SLNode* plist = NULL;SLTPushFront(&plist,520 );SLTPushBack(&plist,1);SLTPushBack(&plist,1);SLTPushFront(&plist,520);SLTPrint(plist);return 0;
}
运行结果:

5. 尾删函数(SLTPopBack)
定义函数:

实现函数:
void SLTPopBack(SLNode** pphead) //尾删
{assert(pphead);assert(*pphead);if ((*pphead)->next== NULL){free(*pphead);*pphead = NULL;}else{SLNode* prev = NULL;SLNode* tail = *pphead;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;}
}
函数测试:
int main()
{SLNode* plist = NULL;SLTPushFront(&plist,520 );SLTPushBack(&plist,1314);SLTPushBack(&plist,00544);SLTPopBack(&plist);SLTPrint(plist);return 0;
}
运行结果:

6. 头删函数(SLTPopFront)
定义函数:

实现函数:
void SLTPopFront(SLNode** pphead) //头删
{assert(*pphead);SLNode* tail = *pphead;tail = tail->next;free(*pphead);*pphead = tail;
}
函数测试:
int main()
{SLNode* plist = NULL;SLTPushFront(&plist,5201314);SLTPushBack(&plist,00544);SLTPushBack(&plist,44944);SLTPopFront(&plist);SLTPrint(plist);return 0;
}
运行结果:

小插曲,pos查找函数 SLTFind
用来确定pos位置,方便后面调用
实现函数:
SLNode* SLTFind(SLNode** pphead, SLNDataType x) //pos的查找函数
{assert(pphead);SLNode* cur = *pphead;while (cur){if (cur->val == x){return cur;}cur = cur->next;}return NULL;
}
7. “插入指定位置前”函数(SLTInster)
定义函数:

实现函数:
void* SLTInster(SLNode** pphead, SLNode* pos, SLNDataType x) //指定位置前面插入
{assert(pos);assert(pphead);assert(*pphead);SLNode* node = CreateNode(x);if (*pphead == pos){node->next = *pphead;*pphead = node;}SLNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}cur->next = node;node->next = pos;
}
函数测试:
int main()
{SLNode* plist =NULL;SLTPushBack(&plist,1);SLTPushBack(&plist,2);SLTPushBack(&plist,3);SLNode* Find = SLTFind(&plist, 3);SLTInster(&plist,Find,123);SLTPrint(plist);return 0;
}
运行结果:
如同在第一个值为3的节点前面插入了123;

8.“删除指定位置后”函数
定义函数:

实现函数:
void* SLTEraseAfter(SLNode* pos) //指定位置后面删除
{assert(pos && pos->next);SLNode* del = pos->next;pos->next = del->next;free(del);
}
函数测试:
int main()
{SLNode* plist =NULL;SLTPushBack(&plist,520);SLTPushBack(&plist,2);SLTPushBack(&plist,520);SLNode* Find = SLTFind(&plist, 2);SLTEraseAfter(Find);SLTPrint(plist);return 0;
}
运行结果:
如图在第一个值为520的节点后面删除了小3;

9.销毁单链表函数SLTDestroy
定义函数:

实现函数:
void SLTDestroy(SLNode** pphead) //销毁单链表
{assert(pphead);SLNode* cur= *pphead;while (cur){SLNode* next = cur;free(cur);cur = next;}*pphead = NULL;
}
测试函数:
int main()
{SLNode* plist =NULL;SLTPushBack(&plist,1);SLTPushBack(&plist,2);SLTPushBack(&plist,3);SLTDestroy(&plist);return 0;
}
结语
感谢您阅读我的博客,我希望您能从中获得一些启发和帮助。如果您喜欢这篇博客,请分享给您的朋友,也欢迎留下您的评论和反馈。您的支持是我继续分享和创作的动力。谢谢!希望我们能在未来的博客中再次相见。祝您一切顺利,期待与您再次相会!
相关文章:
单链表原来是这样实现的!
文章目录 前言1. 链表的概念及结构1.1在链表里,每节“车厢”是什么样的呢?1.2为什么还需要指针变量来保存下⼀个节点的位置? 2. 单链表的实现1. 定义结构体(Seqlist)2. 打印函数(SLTPrint)小插曲,创建节点函数CreateNode3. 尾插函…...
excel一个单元格换行方法
要是在同一个单元格内输入文字输入不下的话,我们是可以进行同一个单元格换行设置的,而且换行的方法也是有很多种,下面我们就一起来看一下有哪些方法吧。 excel一个单元格换行方法: 方法一: 1、我们可以直接按下alte…...
echart一键生成迁徙图
echart_move 介绍 echart迁徙图,选择起点和目的地生成迁徙图 软件架构 html echarts js 使用说明 将文件放到同一目录下打开index.html即可 默认是小飞机图标,如果想修改图标,将图片放到同一目录,如1.svg 代码修改为对应位…...
开发、测试、生产环境
开发环境:开发环境是程序猿们专门用于开发的服务器,配置可以比较随意, 为了开发调试方便,一般打开全部错误报告。简单讲就是项目尚且处于编码阶段,一般这时候会把代码放在开发环境中,不会放在生产环境中。 …...
红队攻防文库文章集锦
再救你一次,不要让欲望击溃你的意志 0.红队攻防 1.红队实战 红队攻防之特殊场景上线cs和msf CVE-2021-42287&CVE-2021-42278 域内提权 红队攻防之Goby反杀 红队攻防实战之钉钉RCE 红队攻防实战之从边界突破到漫游内网(无cs和msf) 红队攻防实战系列一之C…...
Vue框架学习笔记——键盘事件
文章目录 前文提要键盘事件(并不是所有按键都能绑定键盘事件)常用的按键不同的tab和四个按键keyCode绑定键盘事件(不推荐)Vue.config.keyCode.自定义键名 键码 神奇的猜想div标签和click.enterbutton标签和click.enter 前文提要 …...
Windows安装mysql8.0
官网地址:MySQL :: MySQL Community Downloads 选择相应版本信息下载 默认选择点击下一步 默认配置点击next 设置密码 默认配置...
Linux C++网络编程-王健伟
文章目录 1-1课程详细介绍1-2环境搭建详细介绍2-1nginx简介、选择理由、安装和使用2-2nginx整体结构、进程模型3-1学习nginx源码前的准备工作3-2nginx源码学法,终端和进程的关系说3-3信号的概念、认识、处理动作3-4Unix/Linux体系结构、信号编程初步3-5信号编程进阶…...
接收网络包的过程—— IP层->TCP层->Socket层
在 tcp_v4_rcv 中,得到 TCP 的头之后,我们可以开始处理 TCP 层的事情。因为 TCP 层是分状态的,状态被维护在数据结构 struct sock 里面,因而我们要根据 IP 地址以及 TCP 头里面的内容,在 tcp_hashinfo 中找到这个包对应…...
HTTP 响应头信息
HTTP 响应头信息 HTTP请求头提供了关于请求,响应或者其他的发送实体的信息。 在本章节中我们将具体来介绍HTTP响应头信息。 应答头说明Allow服务器支持哪些请求方法(如GET、POST等)。Content-Encoding文档的编码(Encode&#x…...
Android获取原始图片Bitmap的宽高大小尺寸,Kotlin
Android获取原始图片Bitmap的宽高大小尺寸,Kotlin val options BitmapFactory.Options()options.inJustDecodeBounds trueval decodeBmp BitmapFactory.decodeResource(resources, R.mipmap.p1, options)//此时,decode出来的decodeBmp宽高并不是原始图…...
数据结构之数组:简介、特性与应用
文章目录 🌾引言🌾数组的定义与特性🌿数组的定义🌿数组的特性🌿数组的优缺点 🌾数组的应用场景🍁数组的基本应用🍁动态数组(Dynamic Array)🍁多维…...
Hexo 还是 Hugo?Typecho 还是 Wordpress?读完这篇或许你就有答案了!
Hexo 首先介绍的是 Hexo,这也是咕咕没买服务器之前折腾的第一个博客。 演示站点:https://yirenliu.cn 用的主题是 butterfly,想当年刚用的时候,作者还没建群,现在 qq 群都有上千人了,GitHub 上的星星数量也有 2.7k 了。 优点 如果你不想买服务器,但也想折腾一个博客,…...
ChatGPT重磅升级!集简云支持GPT4 Turbo Vision, GPT4 Turbo, Dall.E 3,Whisper等最新模型
在11月7日凌晨,OpenAI全球开发者大会宣布了 GPT-4的一次大升级,推出了 GPT-4 Turbo号称为迄今为止最强的大模型。 此次GPT-4的更新和升级在多个方面显示出强大的优势和潜力。为了让集简云用户能快速体验新模型的能力,我们第一时间整理了大会发…...
Oracle 中的操作符
1.union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序; SELECT * FROM emp WHERE sal < 1500 UNION SELECT * FROM emp WHERE sal BETWEEN 1000 AND 2000 order by 1 2.union All:对两个结果集进行并集操…...
python之UDP网络应用程序开发
文章目录 版权声明UDP网络应用程序开发UDP初识UDP知识要点socket类的使用UDP发送数据开发流程分析UDP服务客户端通信栗子UDP广播发送 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明,所有版权属于黑马程序员或相关权利人所有。…...
中低压MOSFET 2N7002W 60V 300mA 双N通道 SOT-323封装
2N7002W小电流双N通道MOSFET,电压60V电流300mA,采用SOT-323封装形式。超高密度电池设计,适用于极低的ros (on),具有导通电阻和最大直流电流能力,ESD保护。可应用于笔记本中的电源管理,电池供电系统等产品应…...
kafka的设计原理
文章目录 1 Kafka简介2 Kafka的架构2.1 Kafka 一些重要概念2.2 工作流程2.3 副本原理2.4 分区和主题的关系2.5 生产者2.5.1 分区可以水平扩展2.5.2 分区策略 2.6 消费者2.6.1 消费方式2.6.2 分区分配策略 2.7 数据可靠性保证2.7.1 副本数据同步策略2.7.2 ACK 应答机制2.7.3 可靠…...
CANdelaStudio 使用教程5 编辑DID
文章目录 在哪编辑DID的分类编辑快照数据添加 DID 在哪编辑 DID的分类 编辑快照数据 添加 DID...
RESTful API 架构快速入门 Flask实现
RESTful 简介 1.1 为什么要使用 RESTful 架构? Representational State Transfer(REST)是一种面向资源的架构风格,广泛应用于网络服务的设计和开发。使用RESTful架构有以下几个优点: 简单性和可扩展性: RE…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
