C语言数据结构基础-单链表

1.链表概念

       在前面的学习中,我们知道了线性表,其中逻辑结构与物理结构都连续的叫顺序表,那么:

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

2.链表组成

单链表元素(节点)由保存的数据和下个单元的地址组成

 

//结点结构体的定义
struct SListNode{int data;struct SListNode* next;
};

(node就是结点的意思)

国际惯例,我们进行typdef

typedef struct SListNode{int data;struct SListNode* next;
}SLTNode;

那么此时我们可不可以在其中定义next的时候也用SLTNode呢?

SLTNode* next;

       当然是不可以的,此时使用的SLTNode还未被定义,编译器还未能识别,使用了就会报错

为什么要用malloc开辟空间?

为了之后删除(使用free函数释放指针指向的空间)的时候方便,进行初始化时用malloc给每一个节点开辟空间

3.单链表各功能的实现

为了便于链表结点的创建和初始化,我们将其初始功能进行封装

SLTNode* SLTBuyNode(SLTDataType x) {SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL) {perror("malloc fail!");exit(1);}newnode->next = NULL;newnode->data = x;return newnode;
}
 1.尾差

基于顺序表的经验,大概分为两种情况,一种是链表为空,另一种是链表不为空

我们首先传入该链表的头节点,通过直接链接或者先遍历再链接。

传一个指针进函数,对指针进行操作(每一个结点都有元素与其指针等级),那么以上函数就算传值调用,并不能让phead真正等于newnode 

此处的传指针就是传值调用,指针作为变量来修改,就应该传指针的地址,才能达到传址调用的目的。

传递一个指针,可以在函数内部直接修改该指针指向空间的内容,但是想修改、操作传递来的指针,就必须传该指针的指针,才能通过该指针的指针来修改指针的内容。 

       先让创建的新结构体的next找到现在的phead(也就是*pphead,因为函数中不再存在phead这个变量)

再把现在处于第一个的结构体(我们刚刚自己创建的newnode)的地址给到phead

形参是实参的拷贝。

void SLTPushBack(SLTNode** pphead, SLTDataType x) {assert(pphead);SLTNode* newnode = SLTBuyNode(x);//链表为空,新节点作为pheadif (*pphead == NULL) {*pphead = newnode;return;}//链表不为空,找尾节点SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}//ptail就是尾节点ptail->next = newnode;
}

为了便于主函数的调用和检验,我们写出能打印其数据的函数

void SLTPrint(SLTNode* phead) {assert(phead);SLTNode* pos = phead;while (pos) {printf("%d->",pos->data);pos = pos->next;}printf("NULL");
}

这样就能检验我们的尾插功能了。 

2.头插

此处同理,我们任然需要传一个二级指针,通过二级指针对链表进行修改。

依然是分两种情况,实现如下:

void SLTPushFront(SLTNode** pphead, SLTDataType x) {assert(pphead);SLTNode* newnode = SLTBuyNode(x);//若为空if (*pphead == NULL) {*pphead = newnode;return;}//链接newnode 和 *ppheadnewnode->next = *pphead;*pphead = newnode;
}

能否调换以下两句的顺序? 

当然不行,否则新节点将自己的地址赋给了自己的next。

由此可见,链表的实现,重在理清个节点之间的链接顺序。

3.尾删

释放空间,让原本倒数第二个结点的next指向NULL(先free,再置NULL)

多个节点时,我们需要先遍历链表找到最后一个节点的前驱节点ptail(原来的倒数第二个节点),删除最后一个节点的同时改变前驱节点的next的值

但如果只有一个节点呢?

if ((*pphead)->next == NULL) {free(*pphead);*pphead = NULL;return;
}

    所以直接先free再置NULL即可 ,但请注意->和*的优先级不同,箭头是最高优先级,所以需要使用括号

void SLTPopBack(SLTNode** pphead) {assert(pphead);//没有节点时assert(*pphead);//只有一个节点时if ((*pphead)->next) {free(*pphead);*pphead = NULL;return;}//多个节点时SLTNode* ptail = *pphead;while (ptail->next->next) {//很明显,只有一个节点的时候过不了,那么我们就需要在多个节点之前写出只有一个节点的情况ptail = ptail->next;}free(ptail->next);ptail->next = NULL;
}

尽管看上去是先写的一个节点,再写的多个节点,但正常逻辑应该是先写多个(通常情况)再考虑一个(特殊情况)

tips:

遍历链表与找链表尾结点是不一样的

(补充一下遍历链表的方法) 

SLTNode* ptail = *pphead;
SLTNode* prev = NULL;
while (ptail->next)
{prev = ptail;ptail = ptail->next;
}
4.头删

如果链表已经为空的话应该直接退出,所以依然分三种情况考虑

void SLTPopFront(SLTNode** pphead) {assert(pphead);//没有节点 一个节点 多个节点assert(*pphead);SLTNode* tmp = *pphead;*pphead = (*pphead)->next;free(tmp);tmp = NULL;//发现此时一个节点和多个节点都能通过这段代码
}

依然是处理pphead和pphead->next的关系,此处又有一个小技巧,如过发现不能很好的直接通过等式调整各个指针所指向的位置,可以通过建立新的变量拷贝需要处理的数据。 

5.指定位置前后的插入

为了能找到指定的位置,我们先写出一个查找函数

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

 为什么要断言链表不为空?因为如果链表为空,传进来的pos也必须为空,矛盾。

pos应当是已知链表(首节点地址为*pphead的)一个具体特定结点,而非NULL

当然,此处也可以不传二级指针只传一级指针,因为我们也可以不需要对传入的指针进行操作,但是为了接口的一致性,也可以都使用二级指针接口

void SLTInsertAfter(SLTNode* pos, SLTDataType x) {assert(pos);SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next=newnode;
}void SLTInsertBefore(SLTNode* phead, SLTNode* pos, SLTDataType x) {assert(pos);assert(phead);if (pos == phead) {SLTPushFront(&phead, x);return;}SLTNode* newnode = SLTBuyNode(x);SLTNode* prev = phead;while (prev->next != pos) {prev = prev->next;}newnode->next = pos;prev->next = newnode;}

为什么在指定位置前插入数据需要头结点的位置,而指定位置后的不需要呢(指定位置之前插入需要三个参数,指定位置之后插入需要两个参数)?

因为根据单链表的特性,除了最后一个节点,所有节点都能通过自己找到下一个节点,但是找不到上一个节点,所以当我们需要再指定位置之前插入数据时,就需要遍历链表来找到指定位置。

6.删除指定位置之后的节点

 此处的条件为pos->next不为空,具体操作就是链接pos,pos->next,pos->next->next之间的关系

void SLTEraseAfter(SLTNode* pos) {assert(pos);if (pos->next == NULL) {return;}//pos pos->next pos->next->nextSLTNode* tmp = pos->next;pos->next = pos->next->next;free(pos->next);pos->next == NULL;
}
7.删除指定位置的节点

同理

void SLTErase(SLTNode* phead, SLTNode* pos) {assert(phead);assert(pos);//刚好是头则执行头删if (phead == pos) {SLTPopFront(&phead);return;}while (phead->next != pos) {phead = phead->next;}phead->next = pos->next;free(pos);pos = NULL;
}

6,7检测如下 

4.链表分类

上文的单链表Slist就是singel linked list(单向不带头不循环链表)

依据不同的特点,共有八种链表

前文提到的头结点与“带头”的头不一样,前者为第一个有效节点,后者是所谓的哨兵位,不存储有效数据 

       虽然链表种类非常多,但是最实用的只有:单链表、双向链表(带头双向循环链表)

本篇中,已经实现了单链表的大多数功能。

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

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

相关文章

计算星期几

今天是2012年4月12日星期四&#xff0c;编写程序&#xff0c;输入今天开始到12月31日之间的任意日期&#xff0c;输出那一天是星期几。如: 输入“5 20”即5月20日&#xff0c;输出应该为sunday. 代码&#xff1a; #include <cstdio> #include <string> using nam…

挑战杯 基于YOLO实现的口罩佩戴检测 - python opemcv 深度学习

文章目录 0 前言1 课题介绍2 算法原理2.1 算法简介2.2 网络架构 3 关键代码4 数据集4.1 安装4.2 打开4.3 选择yolo标注格式4.4 打标签4.5 保存 5 训练6 实现效果6.1 pyqt实现简单GUI6.3 视频识别效果6.4 摄像头实时识别 7 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xf…

综合练习(一)

目录 列出薪金高于部门 30 的所有员工薪金的员工姓名和薪金、部门名称、部门人数 列出与 ALLEN从事相同工作的所有员工及他们的部门名称、部门人数、领导姓名 Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 列出薪金高于部门 30 的所…

搭建LNMP环境并配置个人博客系统

LNMP是Linux&#xff08;操作系统&#xff09;、Nginx&#xff08;Web服务器&#xff09;、MySQL&#xff08;数据库&#xff09;和PHP&#xff08;脚本解释器&#xff09;的组合&#xff0c;常用于部署高性能的动态网站&#xff0c;如WordPress等博客平台 一、安装Linux操作系…

【论文精读】DINOv2

摘要 学习与特定任务无关的预训练表示已经成为自然语言处理的标准&#xff0c;这些表示不进行微调&#xff0c;即可在下游任务上明显优于特定任务模型的性能。其主要得益于使用无监督语言建模目标对大量原始文本进行预训练。 遵循NLP中的这种范式转变&#xff0c;以探索计算机视…

【文生视频】Diffusion Transformer:OpenAI Sora 原理、Stable Diffusion 3 同源技术

文生视频 Diffusion Transformer&#xff1a;Sora 核心架构、Stable Diffusion 3 同源技术 Sora 网络结构提出背景输入输出生成流程变换器的引入Diffusion Transformer (DiT)架构Diffusion Transformer (DiT)总结 OpenAI Sora 设计思路阶段1: 数据准备和预处理阶段2: 架构设计阶…

单片机精进之路-9ds18b20温度传感器

ds18b20复位时序图&#xff0c;先将b20的数据引脚拉低至少480us&#xff0c;然后再将数据引脚拉高15-60us&#xff0c;再去将测传感器的数据引脚是不是变低电平并保持60-240us&#xff0c;如果是&#xff0c;则说明检测到温度传感器&#xff0c;并正常工作。需要在240us后才能检…

K8S存储卷与PV,PVC

一、前言 Kubernetes&#xff08;K8s&#xff09;中的存储卷是用于在容器之间共享数据的一种机制。存储卷可以在多个Pod之间共享数据&#xff0c;并且可以保持数据的持久性&#xff0c;即使Pod被重新调度或者删除&#xff0c;数据也不会丢失。 Kubernetes支持多种类型的存储卷…

宝塔FTP服务设置并结合cpolar内网穿透实现远程传输文件

文章目录 1. Linux安装Cpolar2. 创建FTP公网地址3. 宝塔FTP服务设置4. FTP服务远程连接小结 5. 固定FTP公网地址6. 固定FTP地址连接 宝塔FTP是宝塔面板中的一项功能&#xff0c;用于设置和管理FTP服务。通过宝塔FTP&#xff0c;用户可以创建FTP账号&#xff0c;配置FTP用户权限…

免费的Git图形界面工具sourceTree介绍

阅读本文同时请参阅-----代码库管理工具Git介绍 sourceTree是一款免费的Git图形界面工具&#xff0c;它简化了Git的使用过程&#xff0c;使得开发者可以更加方便地下载代码、更新代码、提交代码和处理冲突。下面我将详细介绍如何使用sourceTree进行这些操作。 1.下载和…

【Vue3】学习computed计算属性

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

WEB漏洞 逻辑越权之支付数据篡改安全

水平越权 概述&#xff1a;攻击者尝试访问与他拥有相同权限的用户的资源 测试方法&#xff1a;能否通过A用户操作影响到B用户 案例&#xff1a;pikachu-本地水平垂直越权演示-漏洞成因 1&#xff09;可以看到kobe很多的敏感信息 2&#xff09;burp抓包&#xff0c;更改user…

光伏预测 | Matlab基于CNN-SE-Attention-ITCN的多特征变量光伏预测

光伏预测 | Matlab基于CNN-SE-Attention-ITCN的多特征变量光伏预测 目录 光伏预测 | Matlab基于CNN-SE-Attention-ITCN的多特征变量光伏预测预测效果基本描述模型简介程序设计参考资料 预测效果 基本描述 Matlab基于CNN-SE-Attention-ITCN的多特征变量光伏预测 运行环境: Matla…

【rust】10 project、crate、mod、pub、use、项目目录层级组织、概念和实战

文章目录 一、项目目录层级组织概念1.1 cargo new 创建同名 的 Project 和 crate1.2 多 crate 的 package1.3 mod 模块1.3.1 创建嵌套 mod1.3.2 mod 树1.3.3 用路径引用 mod1.3.3.1 使用绝对还是相对? 1.3.4 代码可见性1.3.4.1 pub 关键字1.3.4.2 用 super 引用 mod1.3.4.3 用…

[MYSQL数据库]--mysql的基础知识

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、数据库…

linux 文本编辑命令【重点】

目录 vi&vim介绍 vim安装 vim使用 查找命令 find grep 文本编辑的命令&#xff0c;主要包含两个: vi 和 vim vi&vim介绍 作用: vi命令是Linux系统提供的一个文本编辑工具&#xff0c;可以对文件内容进行编辑&#xff0c;类似于Windows中的记事本 语法: vi file…

android开发书籍推荐,android面试复习

笼统来说&#xff0c;中年程序员容易被淘汰的原因其实不外乎三点。 1、输出能力已到顶点。这个人奋斗十来年了&#xff0c;依旧碌碌无为&#xff0c;很明显这人的天花板就这样了&#xff0c;说白了&#xff0c;天赋就这样。 2、适应能力越来越差。年纪大&#xff0c;有家庭&…

双指针问题(Java编写)

日升时奋斗&#xff0c;日落时自省 目录 一、移动零 二、盛水最多的容器 三、快乐数 四、复写零 五、三数之和 六、有效三角形的个数 七、四数之和 一、移动零 题目来源&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目主要内容就是将数组中所有的零移动到…

【Go-Zero】测试API查询信息无法返回数据库信息与api、rpc文件编写规范

【Go-Zero】测试API查询信息无法返回数据库信息与api、rpc文件编写规范 大家好 我是寸铁&#x1f44a; 总结了一篇测试API查询信息无法返回数据库信息与api、rpc文件编写规范的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 问题背景 大家好&#xff0c;我是寸铁&#xff01…

浅析扩散模型与图像生成【应用篇】(二)——ADM

2. Diffusion Models Beat GANs on Image Synthesis 该文基于扩散模型主要做了两方面的工作&#xff1a;一是通过多种方式优化改进了UNet网络结构以提升扩散模型的生成效果&#xff1b;二是提出一种类别引导的条件生成方法&#xff0c;通过在多个数据集上的实验结果表明&#x…