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路径将被发回给交易发起者作为确…

debian 12 配置VNC

一、服务器 1. 安装和启动 服务器安装vnc-server: apt install tigervnc-standalone-server启动(这里使用的是gnome桌面): tigervncserver -xstartup /usr/bin/gnome-session -geometry 1280x960 -localhost no :1这里的:1是d…

长效静态代理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…

滴水逆向 内存分配-文件读写 课后作业

注意事项: 发现win10的记事本文件不适用于下面的代码, 猜测可能需要DLL文件 因此本次使用不需要加载dll的"飞鸽传书"来实现 题目1)-将记事本的.exe文件读取到内存&#xff0c;并返回读取后在内存中的地址. #include<stdio.h> #include<stdlib.h> …

解密Java线程池源码

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

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

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

理财投资-认识期货

文章目录 一、什么是期货二、为啥要有期货三、为啥要有期货与现货相比 一、什么是期货 期货是一种金融衍生品&#xff0c;它指的是买卖双方在期货交易所内&#xff0c;按照规定格式&#xff0c;通过公开竞价的方式达成的&#xff0c;在未来某一特定的时间和地点&#xff0c;以…

Linux 修改远程默认端口-22

1 编辑sshd配置&#xff0c;修改默认的端口 vi /etc/ssh/sshd_config #添加新的端口 port 62222 ps&#xff1a;先添加新的端口&#xff0c;用新端口能远程登录后再注销22端口&#xff0c;防止修改有问题&#xff0c;导致22端口也不能远程登录 2 重启sshd /etc/init.d/sshd r…

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

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

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

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

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

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

Tomcat 启动闪退的通用解决方案

Tomcat 启动闪退通常是由于配置问题、依赖问题或者系统环境问题引起的。以下是一些常见的解决办法: 检查日志文件: 查看 Tomcat 日志文件,通常位于 Tomcat 安装目录下的 logs 文件夹中,特别是 catalina.out 文件,查找错误信息。这些日志可能包含有关启动失败的详细信息,帮…

PAT 1097 Deduplication on a Linked List(25分)

原题链接&#xff1a;PAT 1097 Deduplication on a Linked List&#xff08;25分&#xff09; Given a singly linked list L with integer keys, you are supposed to remove the nodes with duplicated absolute values of the keys. That is, for each value K, only the f…

Footprint Analytics 与 GalaChain 达成战略合作

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

快速了解 Rust 文档注释功能

Rust 的文档注释使用特定的格式&#xff0c;以便通过 rustdoc 工具生成 API 文档。以下是一些 Rust 文档注释的基本要求和建议&#xff1a; 注释格式&#xff1a; 文档注释以三个斜杠 /// 开始&#xff0c;而不是单个或双个斜杠。注释应该紧接在要注释的代码项&#xff08;如函…

算法-栈操作

1047. 删除字符串中的所有相邻重复项 - 力扣&#xff08;LeetCode&#xff09; 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);}…