数据结构(链表)

9f28ba058efc459681a76e553f453b87.png

  🌏个人博客主页:心.c

2690b34b273145b9ae50a55ae78c53a4.gif#pic_center

前言: 最近练习算法回去学了链表,收获挺大的,大概内容整理了一下,语言是用c写的,所以在这里分享给大家,希望大家可以有所收获 

🔥🔥🔥文章专题:链表 

😽感谢大家的点赞👍收藏⭐️评论✍您的一键三连是我更新的动力 💓 


b333ab1b28b447a8a491bd89340ea770.png

链表的概念: 

链表是一种线性数据结构,它不像数组那样在内存中连续存储数据,而是通过节点(每个节点包含数据和指向下一个节点的指针)链接起来形成一个序列。每个元素不仅包含数据,还包含对下一个元素的引用,这种设计允许链表在内存中以灵活和动态的方式分布。

  • 节点: 链表的基本组成单位。每个节点包含数据和一个指向下一个节点的指针。
  • 头结点: 列表中的第一个节点。
  • 尾节点: 列表中的最后一个节点,其指针通常为NULL
  • 指针: 每个节点都有一个指针,用于存储下一个节点的地址。在单向链表中,节点仅指向其后继;在双向链表中,节点还包含一个指向前驱的指针。

 链表的定义:

 链表是一种线性数据结构,链表的元素(通常称为节点)可以在内存的任意位置分散存储。链表中的每个节点包含两部分:一部分是用于存储数据的字段,另一部分是一个指针

//定义节点内容的数据类型
typedef int SLTDateType;
typedef struct SListNode {SLTDateType data;struct SLTNode* next;
}SLTNode;

 下面这个是我对链表的理解与感悟,如果写的有问题希望大佬们可以指出

 b7ce4b81727149d595f39756fa9deff9.png

SLTNode *phead = NULL;

在这个例子中,phead是一个指向SListNode结构体的指针,它是链表的起点。我们通过这个指针来访问和操作链表中的节点。

链表本身是由一系列节点组成的,而我们用来管理和操作链表的主要工具是一个指向链表头结点的指针。这个指针是链表的入口点,通过它可以访问链表中的所有节点。所以,当我们说“链表本身是一个指针”,我们实际上是在指这个头结点指针。但要理解,这个指针指向的是一个结构体(链表的头结点),而链表的全部内容是由多个这样的结构体节点通过指针链接起来的。

链表节点的创建:

因为在进行链表的添加的时候,我们要不停向添加的项创建节点,所以在这里我就写一个创建节点的方法,下面在添加节点的时候就不需要在进行一系列的判断和创建动态内存和添加了

因为malloc创建内存可能会失败,所以我们要加判断语句 if (newNode)来进行判断,如果添加节点newNode成功,我们就将节点newNode所指向的地方赋值,并且返回所创建的节点

//创建链表
SLTNode* SLTBuyNode(SLTDateType x) {SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));//如果创建链表失败if (newNode) {perror("malloc fail");exit(1);}//如果创建成功newNode->data = x;newNode->next = NULL;return newNode;}

 链表的插入:

讲节点的插入和删除讲一下二级指针的概念和在下文中的作用 

!!!传一级指针,我们需要传入一级指针的地址,并把二级指针当作形参来进行传递一级指针的地址,传指针必须传地址!!! 

下文中关于进行节点的删除和添加方法的参数几乎都是二级指针传参,因为在这里我们的返回值是void,我们的节点是一个结构体指针,所以我们要传二级指针来来表示一级指针的地址来传递我们节点本身的地址,也就是我们结构体指针的地址如果我们传的是一级指针,那么我们传的就不是地址而是值,如果传值返回值为void那么我们的值就不会发生变化方法中所进行的改变也只是在指针的副本中,并不会对节点产生本质改变

int main() {SLTNode* plist = NULL;//插入节点SLTPushBack(&plist, 1);//打印节点SLTPrint(plist);
}

第一个节点的内容 *plist

指向第一个节点的指针(就是我们的结构体指针): plist

指向第一个节点的指针的地址&plist

尾部插入节点:

*pphead 是我们的结构体指针   pphead是指向我们结构体指针的指针(也就是二级指针)

插入时先判断参数是否为NULL,如果为空,就停止程序,如果第一个结构体指针的内容为NULL(是否存放地址),就直接将创建新节点的内容赋值到第一个结构体指针中,如果第一个结构体指针内容不为空,那么就通过while判断找到最后一个结构体指针,然后将最后一个结构体指针内容中的next指向我们新创建的节点的内容因为如果第一个结构体指针内容为NULL的话就不能对ptail->next = newNode;进行判断了,否则会报错,所以我们要分开写

//尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x) {//判断是否存在链表(传入是否为NULL)assert(pphead);//创建链表SLTNode* newNode = SLTBuyNode(x);//如果指向第一个节点的指针为空if (*pphead==NULL) {*pphead = newNode;}else {SLTNode* ptail = *pphead;while (ptail->next) {ptail = ptail->next;}ptail->next = newNode;}
}
头部插入节点:

在头部插入节点比较简单,也是先判断传参是否为NULL,如果不为NULL,那么将第一个节点所指向的内容赋值给我们的新节点,然后将我们创建的节点内容指向我们的第一个节点,并且将第一个节点改为我们创建的新节点

//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x) {assert(pphead);SLTNode* newNode = SLTBuyNode(x);newNode->next = *pphead;//将头结点赋给新创建的节点*pphead = newNode;
}
 在指定位置之前插入节点: 

在插入节点之前先保证我们的链表和节点不为空,还要保证我们的节点pos不为空,处理完这些我们就要进行分析了,如果我们想实现在pos之前插入数据,我们要得到pos之前的节点,然后进行插入,但是当我们的pos是我们的第一个节点,那么我们就不需要找到之前的节点然后进行插入了,可以直接执行我们头插的方法了


//在指定位置之前插入节点
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x) {//判断链表是否为空assert(pphead&&*pphead);assert(pos);//创建新节点SLTNode* newNode = SLTBuyNode(x);//如果为头插if (*pphead == pos) {SLTPushFront(pphead, x);}else {//找到pos之前的节点SLTNode* prev = *pphead;while (prev != pos) {prev = prev->next;}newNode->next = pos;prev->next = newNode;}
}
在指定位置之后插入节点:

当在指定位置插入节点时,我们就不需要头结点pphead了,我们只需要找到我们的pos节点,然后直接进行插入就可以了

//在指定位置之后插入节点
void SLTInsertAfter(SLTNode* pos, SLTDateType x) {assert(pos);SLTNode* newNode = SLTBuyNode(x);newNode->next = pos->next;pos->next = newNode;
}

 链表的删除:

尾部删除节点:

删除节点比较简单,分两种情况,第一个就是多个链表,我们在这里只需要找到最后两个节点,然后将最后最后一个节点释放,然后赋值为NULL,然后将倒数第二个节点的内容next指向的地址也赋值为NULL,防止野指针的出现,但是还要一个情况,当我们的链表只有一个节点时我们根本不需要上面那个方法了,只需要将第一个节点也就是我们的最后一个节点删除掉,然后将结构体指针赋值为NULL就可以了


//尾删
void SLTPopBack(SLTNode** pphead) {//链表不为空也不指向空assert(pphead && *pphead);if ((*pphead)->next == NULL) {free(*pphead);*pphead = NULL;}else {//定义倒数第二个节点SLTNode* prev = *pphead;//定义最后一个节点SLTNode* ptail = *pphead;while (ptail->next) {prev = ptail;ptail = ptail->next;}free(ptail);ptail = NULL;prev->next = NULL;}
}
头部删除节点:

头删链表比尾删链表简单的多,这里我们不需要判断那么多情况,在这里我们只需要获得第二个节点,然后将第一个节点释放掉,赋值为NULL,然后将我们的第一个结构体指针内容换成我们的第二个节点,第二个节点是否为NULL无所谓 ,不会影响后续添加

//头删
void SLTPopFront(SLTNode** pphead) {assert(pphead && *pphead);SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}
删除pos节点:

 当我们删除pos节点我们需要分两种情况,第一种就是多个节点,我们正常获取pos之前的节点,然后删除一个节点,将前一个节点连接我们的后一个节点,还要一种就是当我们只有一个节点时,将直接使用头删方法

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos) {assert(pphead && *pphead);assert(pos);//如果节点是第一个if (pos == *pphead) {SLTPopFront(pphead);}else {SLTNode* prev = *pphead;while (prev->next != pos) {prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}}
删除pos之后的节点:

删除pos之后的节点也很简单,这里我们就需要获得pos节点,然后在获得pos之后要删除的节点,然后将我们要删的节点的下一个节点赋值给我们pos节点的next,然后进行删除赋值 

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos) {assert(pos&&pos->next);//获取pos后面的一个节点SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}

 给大家补充一个方法就是打印链表的方法


//打印链表
void SLTPrint(SLTNode* phead) {SLTNode* pcur = phead;while (pcur) {printf("%d", pcur->data);pcur = pcur->next;}printf("NULL\n");
}

讲到这里就结束了,谢谢大家的观看

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

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

相关文章

2024年技校大数据实验室建设及大数据实训平台整体解决方案

随着信息技术的迅猛发展,大数据已成为推动产业升级和社会进步的重要力量。为适应市场需求,培养高素质的大数据技术人才,技校作为职业教育的重要阵地,亟需加强大数据实验室的建设与实训平台的打造。本方案旨在提出一套全面、可行的…

二维码的生成与识别(python)

二维码生成 from PIL import Image import qrcode from qrcode.image.styledpil import StyledPilImage from qrcode.image.styles.colormasks import SolidFillColorMask from qrcode.image.styles.moduledrawers import SquareModuleDrawer# 创建二维码对象 qr qrcode.QRCo…

vue3在元素上绑定自定义事件弹出虚拟键盘

最近开发中遇到一个需求: 焊接机器人的屏幕上集成web前端网页, 但是没有接入键盘。这就需要web端开发一个虚拟键盘,在网上找个很多虚拟键盘没有特别适合,索性自己写个简单的 图片: 代码: (代码可能比较垃圾冗余,也没时间优化,凑合看吧) 第一步:创建键盘组件 为了方便使用…

【Django】 读取excel文件并在前端以网页形式显示-安装使用Pandas

文章目录 安装pandas写views写urls安装openpyxl重新调试 安装pandas Pandas是一个基于NumPy的Python数据分析库,可以从各种文件格式如CSV、JSON、SQL、Excel等导入数据,并支持多种数据运算操作,如归并、再成形、选择等。 更换pip源 pip co…

Flink SQL 实时读取 kafka 数据写入 Clickhouse —— 日志处理(三)

文章目录 前言Clickhouse 表设计adlp_log_local 本地表adlp_log 分布式表 Flink SQL 说明创建 Source Table (Kafka) 连接器表创建 Sink Table (Clickhouse) 连接器解析 Message 写入 Sink 日志查询演示总结 前言 在之前的文章中,我们总结了如何在 Django 项目中进…

构建智慧水利系统,优化水资源管理:结合物联网、云计算等先进技术,打造全方位、高效的水利管理系统,实现水资源的最大化利用

本文关键词:智慧水利、智慧水利工程、智慧水利发展前景、智慧水利技术、智慧水利信息化系统、智慧水利解决方案、数字水利和智慧水利、数字水利工程、数字水利建设、数字水利概念、人水和协、智慧水库、智慧水库管理平台、智慧水库建设方案、智慧水库解决方案、智慧…

spring-boot3.x整合Swagger 3 (OpenAPI 3) +knife4j

1.简介 OpenAPI阶段的Swagger也被称为Swagger 3.0。在Swagger 2.0后,Swagger规范正式更名为OpenAPI规范,并且根据OpenAPI规范的版本号进行了更新。因此,Swagger 3.0对应的就是OpenAPI 3.0版本,它是Swagger在OpenAPI阶段推出的一个…

产品系统的UI暗色系和浅色系模式切换是符合人体视觉工程学的设计

视觉革命:UI设计中的暗夜与黎明 UI设计如同夜空中最亮的星辰,引领着用户穿梭于信息的海洋。而今,一场视觉革命正在悄然上演,它关乎于我们的眼睛,关乎于我们的体验——那就是产品系统的UI暗色系和浅色系模式的切换。如…

Android lmkd机制详解

目录 一、lmkd介绍 二、lmkd实现原理 2.1 工作原理图 2.2 初始化 2.3 oom_adj获取 2.4 监听psi事件及处理 2.5 进程选取与查杀 2.5.1 进程选取 2.5.2 进程查杀 三、关键系统属性 四、核心数据结构 五、代码时序 一、lmkd介绍 Android lmkd采用epoll方式监听linux内…

SpringBoot整合阿里云短信业务

详细介绍SpringBoot整合阿里云短信服务的每一步过程,同时会将验证码存放到Redis中并设置过期时间,尽量保证实战的同时也让没做过的好兄弟也能实现发短信的功能~ 1. 注册阿里云账号和创建Access Key 首先,你需要注册一个阿里云账号&#xff0…

【JavaEE初阶】Thread类及常见方法

目录 📕 Thread类的概念 📕 Thread 的常见构造方法 📕 Thread 的几个常见属性 📕 start()-启动一个线程 📕 中断一个线程 🚩 实例一 🚩 实例二 🚩 实例三 📕 jo…

昇思MindSpore学习入门-数据处理管道支持python对象

数据处理管道中的特定操作(如自定义数据集GeneratorDataset、自定义map增强操作、自定义batch(per_batch_map...))支持任意Python类型对象作为输入。为了支持此特性,数据管道使用了Python(dict)字典去管理不同类型的对象。与其他类型相比&…

康康近期的慢SQL(oracle vs 达梦)

近期执行的sql,哪些比较慢? 或者健康检查时搂一眼状态 oracle: --最近3天内的慢sql set lines 200 pages 100 col txt for a65 col sql_id for a13 select a.sql_id,a.cnt,a.pctload,b.sql_text txt from (select * from (select sql_id,co…

基于微信小程序的自习室选座系统/基于Java的自习室选座系统/自习室管理系统的设计与实现

获取源码联系方式请查看文章结尾🍅 摘要 自习室选座是学校针对用户必不可少的一个部分。在学校的整个过程中,学生担负着最重要的角色。为满足如今日益复杂的管理需求,各类微信小程序自习室选座也在不断改进。本课题所设计的小程序自习室选座系…

【C#】Visual Studio2022打包依赖第三方库的winForm程序为exe

0.简介 IDE:VS2022 平台:C# .NetFramework4.7.2 WinForm界面 有GDAL、EEplus第三方库的依赖,所以在其他未安装环境的电脑中功能无法使用。 1. 安装 1.1 运行文件输出 在VS扩展中选择管理扩展,安装:Microsoft Visua…

SpringBoot上传超大文件导致OOM,完美问题解决办法

问题描述 报错: Caused by: java.lang.OutOfMemoryError at java.io.ByteArrayOutputStream.hugeCapacity(ByteArrayOutputStream.java:123) ~[?:1.8.0_381] at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:117) ~[?:1.8.0_381] at java.…

MQTTX连接华为云IoTDA

目录 华为IoTDA平台 MQTTX连接参数的设置 物模型的构建 属性上报 基本数据格式 时戳 我以前上课都是用巴法云服务器来演示MQTT的,前几天因为测试工业互联网关使用了华为的IoTDA,觉得也不算太复杂,今天尝试用MQTTX连接华为云&#xff0c…

【ARM】MDK-STM32g0xx.h文件与Define规则记录

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 记录问题STM32g0xx.h等有关ST的可读文件,尽量勿修改文件格式及对其代码进行添加和删减,记录查找问题的过程中的疑惑,并如何给予客户正确的回复,帮助销售完成验收&…

CefSharp音视频编译与免费下载

注:Cefharp 音频和视频播放编译,生成相应的dll文件,从而支持项目开发。 建议编译至少 16G 的 RAM和至少 250G 的 SSD。该脚本以 E 盘为例,您需要在 E 盘上手动创建 cef 文件夹。禁止在转载后通过发布其他平台向用户收取下载费用。…

新形势下职业教育大数据人才培养策略

一、引言 随着信息技术的飞速发展,大数据已成为驱动经济社会变革的关键力量。在新形势下,职业教育作为技术技能人才培养的重要阵地,面临着如何适应大数据时代要求、提升人才培养质量的紧迫任务。当前,职业教育在大数据人才培养方…