C语言进阶|单链表的实现

 ✈链表的概念和结构

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

链表的结构跟火车车厢相似,淡季时车次的车厢会相应减少,旺季时车次的车厢会额外增加几节。只需要将火车里的某节车厢去掉/加上,不会影响其他车厢,每节车厢都是独立存在的

车厢是独立存在的,且每节车厢都有车门。”想蒙一下这样的场景,“假设每节车厢的车门都是锁上的状态,需要不同的钥匙才能解锁,每次只能携带一把钥匙的情况下如何从车头走到车尾?
最简单的做法:每节车厢里都放一把下一节车厢的钥匙。在链表里,每节“车厢”是什么样的呢?

与顺序表不同的是,链表里的每节”车厢”都是独立申请下来的空间,我们称之为“结点/节点”节点的组成主要有两个部分:当前节点要保存的数据和保存下一个节点的地址(指针变量)。图中指针变量plist保存的是第一个节点的地址,我们称plist此时“指向”第一个节点,如果我们希望plist“指向”第二个节点时,只需要修改plist保存的内容为0x0012FFA0。
为什么还需要指针变量来保存下一个节点的位置?
链表中每个节点都是独立申请的(即需要插入数据时才去申请一块节点的空间),我们需要通过指针变量来保存下一个节点位置才能从当前节点找到下一个节点。
结合前面学到的结构体知识,我们可以给出每个节点对应的结构体代码;
假设当前保存的节点为整型:

typedef int SLTDataType;typedef struct SListNode
{SLTDataType data; //节点数据struct SListNode* next; //指针保存下个节点的地址
}SLTNode;

当我们想要保存一个整型数据时,实际是向操作系统申请了一块内存,这个内存不仅要保存整型数据,也需要保存下一个节点的地址(当下一个节点为空时保存的地址为空)。
当我们想要从第一个节点走到最后一个节点时,只需要在前一个节点拿上下一个节点的地址(下一个节点的钥匙)就可以了。

给定的链表结构中,如何实现节点从头到尾的打印?

 思考:当我们想保存的数据类型为字符型、浮点型或者其他自定义的类型时,该如何修改?
补充说明:
1、链式机构在逻辑上是连续的,在物理结构上不一定连续
2、节点一般是从堆上申请的
3、从堆上申请来的空间,是按照一定策略分配出来的,每次申请的空间可能连续,可能不连续

✈单链表的实现

//头文件
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data; //节点数据struct SListNode* next; //指针保存下个节点的地址
}SLTNode;
//查看单链表
void SLTPrint(SLTNode* phead);
//头部插入删除/尾部插入删除
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);

🚀需要调用的函数 

//查找最后一个
SLTNode* SLTFindLast(SLTNode* phead)
{assert(phead);while (phead->next!=NULL){phead = phead->next;}return phead;
}
//查找上一个
SLTNode* SLTPrevious(SLTNode* phead, SLTNode* x)
{assert(phead);while (phead->next != x){phead = phead->next;}return phead;
}
//创建变量
SLTNode* SLTBuyNode(SLTDataType x)
{SLTNode* tmp = (SLTNode*)malloc(sizeof(SLTNode));if (!tmp){perror("malloc error");exit(1);}tmp->data = x;tmp->next = NULL;return tmp;
}

🚀查看单链表 

//查看单链表
void SLTPrint(SLTNode* phead)
{while (phead != NULL){printf("%d->", phead->data);phead = phead->next;}printf("NULL\n");
}

🚀简单的插入删除 

//头部插入删除/尾部插入删除
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* tmp = SLTBuyNode(x);//如果链表为空if (*pphead == NULL){*pphead = tmp;}else//如果链表不空{SLTFindLast(*pphead)->next = tmp;}
}void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newNode = SLTBuyNode(x);SLTNode* tmp = *pphead;*pphead = newNode;newNode->next = tmp;}
void SLTPopFront(SLTNode** pphead)
{assert(pphead);//链表不能为空assert(*pphead);SLTNode* tmp = *pphead;*pphead = (*pphead)->next;free(tmp);tmp = NULL;
}
void SLTPopBack(SLTNode** pphead)
{assert(pphead);//链表不能为空assert(*pphead);SLTNode* Last = SLTFindLast(*pphead);SLTNode* Previous = SLTPrevious(*pphead, Last);Previous->next = NULL;free(Last);}

🚀查找 

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{assert(phead);while (phead != NULL){if (phead->data == x){return phead;}phead = phead->next;}return NULL;
}

🚀在指定位置之前插入数据 

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(*pphead);SLTNode* Prepos = SLTPrevious(*pphead, pos);SLTNode* newnode = SLTBuyNode(x);Prepos->next = newnode;newnode->next = pos;}

🚀删除指定位置的节点 

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(*pphead);assert(pos);SLTNode* Prepos = SLTPrevious(*pphead, pos);Prepos->next = Prepos->next->next;free(pos);
}

🚀在指定位置之后插入数据 

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);SLTNode* tmp = pos->next;pos->next = newnode;newnode->next = tmp;
}

🚀删除指定位置之后的节点 

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* tmp = pos->next;pos->next = pos->next->next;free(tmp);
}

🚀销毁链表 

//销毁链表
void SListDesTroy(SLTNode** pphead)
{assert(pphead);//assert(*pphead);while (*pphead != NULL){SLTNode* tmp = *pphead;*pphead = (*pphead)->next;free(tmp);}
}

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

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

相关文章

BSV区块链协会上线首个版本的ARC交易处理器

​​发表时间:2024年3月28日 BSV区块链协会近期上线了首个版本的ARC交易处理器。ARC是一项区块链交易处理服务,能在通过P2P网络广播交易之前验证并存储相关的交易。一旦新区块被挖出,一条与该交易相关的Merkle路径将被发回给交易发起者作为确…

长效静态代理IP如何改变你的SEO和网络营销策略?

长效静态代理IP为SEO和网络营销专家提供了一个强大的工具,通过这种技术,可以突破传统的限制,以全新的视角和方法优化其在线策略。这不仅增强了企业的市场竞争力,也为实现更高效、更精准的营销目标提供了可能。 一、长效静态代理IP…

Vue面试经验

Vue编译时声明周期的执行顺序 Vue中父子组件渲染顺序(同步引入子组件:import Son from ‘/components/son’ ) 父子组件编译时的生命周期执行顺序 这里修改data数据时也修改了dom,如过知识通过按钮对数据进行操作,那…

kafka大数据采集技术实验(未完待续)

Kafka环境搭建 下载地址:https://link.zhihu.com/?targethttps%3A//kafka.apache.org/downloads解压启动zookeeper bin/zookeeper-server-start.sh config/zookeeper.properties需要注意的是 : " c o n f i g / z o o k e e p e r . p r o p e r t i e s &q…

解密Java线程池源码

一、线程池中的保活和回收源码分析 1、线程池中线程的创建时机 1、核心线程创建时机 在研究线程池的源码前首先想一个问题 public class Main {public static void main(String[] args) {ThreadPoolExecutor executor new ThreadPoolExecutor(10, 20, 0l, TimeUnit.MILLIS…

从Linux角度具体理解程序翻译过程-----预处理、编译、汇编、链接

目录 前言: 翻译过程 1.预处理 2.编译 3.汇编 4.链接 Linux下对其理解: 1.预处理 拓展: Linux下文件信息: 文件类型: 硬链接数: 文件拥有者: 文件所属组: other&#x…

区块链安全应用-------压力测试

基于已有的链进行测试(build_chain默认建的链 四个节 点): 第一步:搭链 1. 安装依赖 在ubuntu操作系统中,操作步骤如下: sudo apt install -y openssl curl 2. 创建操作目录, 下载安装脚本 ## 创建操作…

3个比较不错的Linux云音乐应用程序整理

在现代音乐流媒体时代,基于云的音乐应用程序因其便利性和可访问性而变得非常流行。Linux 用户尤其寻求可靠且功能丰富的音乐播放器来无缝地享受他们喜爱的音乐。 在这里,我们探讨了三个最好的基于云的音乐应用程序,每个应用程序都提供专为 L…

Java Web 网页设计(1)

不要让追求之舟停泊在幻想的港湾 而应扬起奋斗的风帆 驶向现实生活的大海 网页设计 1.首先 添加框架支持 找到目录右键添加 找到Web Application选中 点击OK 然后 编辑设置 找到Tomcat--local 选中 点击OK 名称可以自己设置 找到对应文件夹路径 把Tomcat添加到项目里面 因为…

【Hadoop】-HDFS的Shell操作[3]

目录 前言 一、HDFS集群启停命令 1.一键启停脚本可用 2.独立进程启停可用 二、文件系统操作命令 1、创建文件夹 2、查看指定目录下内容 3、上传文件到HDFS指定目录下 4、查看HDFS文件内容 5、下载HDFS文件 6、拷贝HDFS文件 7、追加数据到HDFS文件中 8、HDFS数据移…

哪吒汽车把最后的翻身筹码,全压在了这辆新车上

正如比亚迪王传福所说,新能源车市场已进入惨烈淘汰赛环节。 近几年国内新能源车销量增长势头迅猛,仅过去的 2023 年产销便分别达 958.7 万辆和 949.5 万辆,同比增长 35.8% 和 37.9%。 销量高速增长背后自然也带来了越来越激烈的竞争。 过去…

Footprint Analytics 与 GalaChain 达成战略合作

​ Footprint Analytics 宣布与 GalaChain 达成战略合作。GalaChain 是 Gala 旗下的 Layer 1 区块链。此次合作标志着双方在游戏(包括 Gala Games) 、娱乐和金融等多个行业的区块链生态系统革新方面迈出了重要的一步。 GalaChain 致力于满足企业级项目的广泛需求&…

算法-栈操作

1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode) class Solution { public:string removeDuplicates(string s) {string stack;for(char& ch:s){if(stack.size()>0&&chstack.back()){stack.pop_back();}else{stack.push_back(ch);}…

AI大模型实现软件智能化落地实践

1、什么是大模型 大型语言模型(Large Language Model,LLM;Large Language Models,LLMs)。 大语言模型是一种深度学习模型,特别是属于自然语言处理(NLP)的领域,一般是指包含数干亿&…

Pandas 模块-操纵数据(11)-二元运算--超级add、sub、mul、div、mod、pow等等

目录 1. DataFrame.add 1.1 DataFrame.add 语法结构 1.2 DataFrame.add 参数说明 1.3 DataFrame.add 用法示例 1.3.1 正常的使用 1.3.2 需要注意类型相符合 2. DataFrame.sub 2.1 DataFrame.sub 语法结构 2.2 DataFrame.sub 参数说明 2.3 DataFrame.sub 用法示例 3.…

传媒论坛编辑部传媒论坛杂志社传媒论坛杂志2024年第7期目录

专题│场景传播研究 场景传播:一场遮盖自我与寻找自我的博弈 胡沈明; 3 基于CiteSpace的中国场景传播研究热点分析 管倩;粟银慧; 4-610《传媒论坛》投稿:cnqikantg126.com 数字世界的美与危:场景传播的失范与应对之举 王依晗;章洁…

分布式-知识体系

分布式系统 本质就是一堆机器的协同,要做的就是用各种手段来让机器的运行达到预期 分布式业务场景 分布式四纵四横说 基于 MSA(微服务架构)的分布式知识体系 相关概念 – 【摘自网络原文】 节点与网络 节点 传统的节点也就是一台单体的物…

MySQL数据类型:字符串类型详解

MySQL数据类型:字符串类型详解 在MySQL数据库中,字符串数据类型用于存储各种文本信息。这些数据类型主要包括CHAR、VARCHAR、TEXT和BLOB等。 CHAR与VARCHAR CHAR CHAR类型用于存储固定长度的字符串。它的长度在创建表时就已确定,长度范围…

QJ71C24N-R2 三菱Q系列串行通信模块

三菱Q系列串行通信模块是通过串行通信用的RS-232、RS-422/485线路将对方设备与Q系列可编程控制器CPU相连接,以实现如下所示的数据通信的模块。通过使用调制解调器/终端适配器,可以利用公共线路(模拟/数字)实现与远程设备间的数据通信。 QJ71C24N-R2参数说明:串行RS-…

为什么36KbRAM会配置为32K×1,少的那4Kb去哪了?

首先我们需要了解BRAM的相关知识,可以参考下面两篇文章: Xinlinx FPGA内的存储器BRAM全解-CSDN博客 为何有时简单双口RAM是真双口RAM资源的一半-CSDN博客 本问题的背景是: 每个36Kb块RAM也可以配置成深度宽度为64K 1(当与相邻的36KB块RA…