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.mzph.cn/news/708968.shtml

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

相关文章

【软件设计师】多元化多方面了解多媒体技术的内容

🐓 多媒体技术基本概念 多媒体主要是指文字、声音和图像等多种表达信息的形式和媒体,它强调多媒体信息的综合和集成处理。多媒体技术依赖于计算机的数字化和交互处理能力,它的关键是信息压缩技术和光盘存储技术。 亮度 亮度是光作用于人眼时所…

linux+samba共享文件夹-window可以直接上传服务器数据(只能读取不能写入问题)

项目场景: 因为要上传本地瓦片100gb左右,下载再上传时间太长了,最后想到直接下载在服务器,但是下载瓦片软件没有linux版本,于是想到共享文件夹 问题描述 按照这个大佬文档(linuxsamba配置)一切都还好,查…

springboot 注解属性转换字典

1.注解相关功能实现 定义属性注解 import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.vehicle.manager.core.serializer.DicSerializer;import java.lang.annotation.*;/*** a…

OpenAI划时代大模型——文本生成视频模型Sora作品欣赏(十一)

Sora介绍 Sora是一个能以文本描述生成视频的人工智能模型,由美国人工智能研究机构OpenAI开发。 Sora这一名称源于日文“空”(そら sora),即天空之意,以示其无限的创造潜力。其背后的技术是在OpenAI的文本到图像生成模…

家庭游泳池:阳台上可安装的泳池

游泳池可根据场地大小选择安装在室内或室外,这种的泳池规格尺寸相对来说较大,较适合于大型体育场馆、小区配套、健身房等场所。这款家庭泳池与之前的不太一样,不论是从池体材料还是装饰面层都有着很大的差异。 该家庭泳池规格尺寸比较固定&a…

书籍推荐|《使用 ESP32 开发物联网项目(第二版)》

随着物联网技术的迅猛发展,ESP32 因其强大的功能而备受物联网开发者的青睐。在此背景下,资深物联网专家 Vedat Ozan Oner 撰写的《使用 ESP32 开发物联网项目(第二版)》,为开发者提供了全面且深入的指南读物。 资深物…

SpringBoot整合rabbitmq-直连队列,没有交换机(一)

说明&#xff1a;本文章只是springboot和rabbitmq的直连整合&#xff0c;只使用队列生产和消费消息&#xff0c;最简单整合&#xff01; 工程图&#xff1a; A.总体pom.xml <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://…

【精选】Java项目介绍和界面搭建——拼图小游戏 上

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

实施顾问的 IDoc 基础知识

目录 一、前言二、概览三、EDI 标准和 IDOC四、IDOC 术语4.1 IDOC&#xff08;基本&#xff09;类型4.2 IDOC 扩展&#xff08;EXTENSION&#xff09;4.3 IDoc 段4.4 父项 IDoc 段与子项 IDoc 段4.5 入站/出站 IDOC4.6 IDOC方向4.7 合作伙伴4.8 合作伙伴类型4.9 消息类型4.10 流…

在Ubuntu中安装Anaconda和创建虚拟环境(保姆级教学,值得借鉴与信任)

一、下载linux版本的Anaconda 1.方法一&#xff1a;官网下载 https://www.anaconda.com/download#downloads2.方法二&#xff1a;在清华大学开源软件镜像站里下载 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/最后选择了Anaconda3-2022.10-Linux-x86_64.sh进行下…

【EFK】基于K8S构建EFK+logstash+kafka日志平台

基于K8S构建EFKlogstashkafka日志平台 一、常见日志收集方案1.1、EFK1.2、ELK Stack1.3、ELK filbeat1.4、其他方案 二、EFK组件介绍2.1、Elasticsearch组件2.2、Filebeat组件【1】 Filebeat和beat关系【2】Filebeat是什么【3】Filebeat工作原理【4】传输方案 2.3、Logstash组件…

python 中常用的热门库介绍

阅读本文之前请参阅-----如何系统的自学python Python 是一种非常流行的编程语言&#xff0c;它的一个主要优势是拥有一个庞大的生态系统&#xff0c;其中包括许多强大的库。这些库为各种任务提供了解决方案&#xff0c;从数据分析到机器学习&#xff0c;从网络爬虫到图像处理。…

ArmSoM Rockchip系列产品 通用教程 之 CAN 使用

CAN 使用 1. CAN 简介 CAN (controller Area Network)&#xff1a;控制器局域网络总线&#xff0c;是一种有效支持分布式控制或实时控制的串行通信网络。 目前世界上绝大多数汽车制造厂商都采用CAN总线来实现汽车内部控制系统之间的数据通信。 RK3568/RK3588的CAN驱动文件&a…

推荐一款ssh工具 xshell替代品 electerm

下载地址 electerm&#xff1a; https://electerm.github.io/electerm/ windows版本 产品优势 复制粘贴&#xff0c;可以直接使用ctrlc/v 非常的方便 而且不想xshell 需要账号登陆&#xff0c;有更新弹窗&#xff0c;自身集成了sftp 界面设计更新&#xff0c;比MobaXterm的…

2024年值得关注的5款国产低代码开发平台

最近几年&#xff0c;低代码\无代码\零代码技术和快速开发平台比较热门&#xff0c;全球知名低代码平台厂商有&#xff1a;微软Power Platform、西门子Mendix、OutSystems等。我们国内最近几年也有一些信创国产化低代码平台涌现出来&#xff0c;比如&#xff1a;云程、氚云、轻…

【计算机网络】一些乱七八糟内容

MAC Media Access Control 用于在局域网&#xff08;LAN&#xff09;或广域网&#xff08;WAN&#xff09;中实现设备自动接入网络 "载波侦听多路访问"(Carrier Sense Multiple Access) CSMA/CD 是CSMA的升级版本&#xff0c;加入了序列号检测机制。 CSMA/CA 是CSM…

阿里又放大招 EMO:一张照片+音频即可生成会说话唱歌的视频

项目简介 你只需要提供一张你的照片任意的音频文件&#xff0c;就能实现你说任何话或唱任何歌曲的动态视频。同时生成视频的长度和你音频长度相匹配&#xff01;表情非常到位&#xff0c;支持任意语音、任意语速、任意图像。 主要特点和功能 1、音频驱动的人像视频生成&#…

如何利用IP代理高效采集产品数据,打造爆品?

文章目录 一、什么是网络爬虫&#xff1f;二、普通人如何通过网络爬虫赚钱&#xff1f;2.1、心得分享2.2、工具自动化收集信息 三、 动态IP代理3.1、覆盖范围3.2、性价比3.3、教程中心F&Q使用教程 3.4、在网络数据采集中的重要性 四、实战应用案例一&#xff1a;ebay电商【…

lv19 多态 4

1 虚函数 虚函数&#xff08; 基类指针可指向派生类对象&#xff0c; 动态联编&#xff09; 先看示例&#xff0c;不加virtual&#xff0c;不认对象认指针。 #include <iostream>using namespace std;class A{ public:A(){ }~A(){ }void show(){cout<<"AAA…

图神经网络实战——图论

图神经网络实战——图论 0. 前言1. 图属性1.1 有向图和无向图1.2 加权图与非加权图1.3 连通图非连通图1.4 其它图类型 2. 图概念2.1 基本对象2.2 图的度量指标2.2 邻接矩阵表示法 3. 图算法3.1 广度优先搜索3.2 深度优先搜索 小结系列链接 0. 前言 图论 (Graph theory) 是数学…