数据结构基础:3.单链表的实现。

单链表的介绍和实现

  • 一.基本概念
    • 1.基本结构
    • 2.结构体节点的定义:
  • 二.功能接口的实现
    • 0.第一个节点:plist
    • 1打印链表
    • 2创建一个节点
    • 3.头插
    • 4.头删
    • 5.尾插
    • 6.尾删
    • 7.查找
    • 8.在pos之前插入x
    • 9.在pos之后插入x
    • 10.删除pos位置
    • 11.删除pos的后一个位置
    • 12.链表释放
  • 三.整体代码

一.基本概念

1.基本结构

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

逻辑结构:前面的叫做数据域,后面叫做指针域,指针是用来保存下一个节点的地址的。在逻辑上是这样连续的但是在实际的物理结构上面空间上不是连续的。请添加图片描述

物理结构:这些都是节点,在内存中是通过前一个节点保存后一个节点的地址这样的话就可以连续去寻找链表数据。
请添加图片描述

2.结构体节点的定义:

请添加图片描述

二.功能接口的实现

0.第一个节点:plist

如果我们想要创建好一个链表并且去使用他我们需要有这些节点并且通过结构体的成员变量去连接我们的这个结构体构成一个链表的状态因为我们的方向是单向的所以每一次使用的时候我们应该需要知道第一个节点的地址,并且第一个节点它在逻辑上必须处于链表的第一个位置,我们在进行接口的操作都是依赖于我们的第一个节点。(第一个节点如果要变化那么我们的在主函数中的第一个节点的地址就要变化)(地址的变化是需要传二级指针的)

请添加图片描述

1打印链表

打印链表只需要循环遍历一次链表的数据内容。(不需要对第一个节点的地址发生改变)

//打印链表
void SLTprint(SLTNode* plist)
{//循环遍历不去更改头所以不需要传二级指针//打印之前我们需要注意我们是否有数据打印//说明链表已经没有数值或者还没有节点数据assert(plist!=NULL);SLTNode* cur = plist;//一个节点的下一个是空就不打印数据了while (cur){printf("%d->", cur->data);//循环的一个条件cur = cur->next;}printf("NULL\n");}

2创建一个节点

一个新节点的创建需要注意一个参数和一个返回值,参数是我们的节点的数据值,返回的参数是这个节点的地址,因为我们只能通过存储地址的方式进行链表的连接。

//创建一个节点
SLTNode* BuySListNode(STLDatatype x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode*));if (newnode == NULL){perror("malloc file\n");exit(-1);//开辟空间失败直接退出程序}//使用这个节点newnode->data = x;//因为这是一个新的节点我们的下一个数据还没有给它//它现在不需要去存储下一个节点的地址。newnode->next = NULL;return newnode;
}

3.头插

头插:我们的头节点每经过一次头插就要改变前面提过我们去使用链表的时候是需要第一个节点的指针的。这个指针如果改变是需要影响到接口外的实参的。(需要传二级指针改变)

//头插
//头插
void SLTpushfront(SLTNode** pphead, STLDatatype x)
{//插入一个数据需要一个新的节点SLTNode* newnode = BuySListNode(x);//是有数据,说明*pphead不是空。//如果直接改变第一个的地址那么。第二个数据就找不到了。newnode->next = *pphead;*pphead = newnode;
}

4.头删

头删需要把第一个节点给释放,原来的第二个作为新的头,需要对我们的第一个节点进行地址的改变(需要传二级指针)

void SLTpopfront(SLTNode** pphead)
{//删除数据如果没有数据就不去删除assert(*pphead != NULL);//不止一个数据,保存第二个节点的地址SLTNode* newhead = (*pphead)->next;free(*pphead);*pphead = NULL;//释放老节点,拿到新节点*pphead = newhead;
}

5.尾插

不去修改第一个节点,可以传二级也可以传一级。

void SLTpushback(SLTNode** pphead, STLDatatype x)
{SLTNode* newnode = BuySListNode(x);//当没有数据的时候if (*pphead == NULL){//对一个地址的修改*pphead = newnode;}else{SLTNode* cur = *pphead;//下一个是NULL就是尾while (cur->next != NULL){cur = cur->next;}cur->next = newnode;}
}

6.尾删

有可能删除第一个所以需要传二级指针。

//尾删
void SLTpopback(SLTNode** pphead)
{assert(*pphead);//当链表中只剩下最后一个节点的时候,需要把头指针也制空。if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{//找尾SLTNode* cur = *pphead;SLTNode* prev = *pphead;while (cur->next != NULL){//cur下一个是NULL说明现在的这个就是尾prev = cur;cur = cur->next;}//产生野指针的问题,确实释放了但是我们cur的前面一个指向的是一个野指针。free(cur);prev->next = NULL;}
}

7.查找

1.查找的区域不可以为空,返回一个节点地址。

SLTNode* SLTFind(SLTNode* phead, STLDatatype x)
{assert(phead);SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}
}

8.在pos之前插入x

1.如果pos是第一个位置相当于头插可以复用前面的代码也可以自己写一个。
2.有可能会改到头所以必须要传二级指针。

void SLTInsert(SLTNode** pphead, SLTNode* pos, STLDatatype x)
{SLTNode* newnode = BuySListNode(x);if (pos == *pphead){SLTpushfront(pphead, x);}else{SLTNode* cur = *pphead;while (cur->next!=pos){cur=cur->next;}cur->next = newnode;newnode->next = pos;}
}

9.在pos之后插入x

void SLTInsertAfter(SLTNode* pos, STLDatatype x)
{SLTNode* newnode = BuySListNode(x);SLTNode* next = pos->next;pos->next = newnode;newnode->next = next;
}

10.删除pos位置

// 删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos)
{if (pos == *pphead){//头删SLTpopfront(pphead);}else{SLTNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}SLTNode* newhead = cur->next->next;free(pos);pos = NULL;cur->next = newhead;}
}

11.删除pos的后一个位置

// 删除pos的后一个位置
void SLTEraseAfter(SLTNode* pos)
{assert(pos->next != NULL);if (pos->next->next == NULL){free(pos->next);pos->next = NULL;pos->next = NULL;}else{SLTNode* next = pos->next->next;free(pos->next);pos->next = NULL;pos->next = next;}}

12.链表释放

// 单链表的销毁
void SListDestroy(SLTNode** plist)
{assert(plist != NULL);//只需要释放不需要改变,所以一级就可以SLTNode* cur = *plist;while (cur->next!=NULL){SLTNode* next = cur->next;cur->next = NULL;free(cur);cur = NULL;cur = next;SLTprint(cur);}cur->next = NULL;free(cur);cur = NULL;//原来的节点地址被释放,随机值但不是NULL*plist = NULL;
}

三.整体代码

#define _CRT_SECURE_NO_WARNINGS 1#include"SLTNode.h"//打印链表
void SLTprint(SLTNode* plist)
{//循环遍历不去更改头所以不需要传二级指针//打印之前我们需要注意我们是否有数据打印//说明链表已经没有数值或者还没有节点数据assert(plist!=NULL);SLTNode* cur = plist;//一个节点的下一个是空就不打印数据了while (cur){printf("%d->", cur->data);//循环的一个条件cur = cur->next;}//实参是一个空指针但是存贮空指针的这个空间不是printf("NULL\n");}
//创建一个节点
SLTNode* BuySListNode(STLDatatype x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode*));if (newnode == NULL){perror("malloc file\n");exit(-1);//开辟空间失败直接退出程序}//使用这个节点newnode->data = x;//因为这是一个新的节点我们的下一个数据还没有给它//它现在不需要去存储下一个节点的地址。newnode->next = NULL;return newnode;
}//头插
void SLTpushfront(SLTNode** pphead, STLDatatype x)
{//插入一个数据需要一个新的节点SLTNode* newnode = BuySListNode(x);//是有数据,说明*pphead不是空。//如果直接改变第一个的地址那么。第二个数据就找不到了。newnode->next = *pphead;*pphead = newnode;
}//头删
void SLTpopfront(SLTNode** pphead)
{//删除数据如果没有数据就不去删除assert(*pphead != NULL);//不止一个数据,保存第二个节点的地址SLTNode* newhead = (*pphead)->next;free(*pphead);//释放老节点,拿到新节点*pphead = newhead;
}
//尾插
void SLTpushback(SLTNode** pphead, STLDatatype x)
{SLTNode* newnode = BuySListNode(x);//当没有数据的时候if (*pphead == NULL){//对一个地址的修改*pphead = newnode;}else{SLTNode* cur = *pphead;//下一个是NULL就是尾while (cur->next != NULL){cur = cur->next;}cur->next = newnode;}
}
//尾删
void SLTpopback(SLTNode** pphead)
{assert(*pphead);//当链表中只剩下最后一个节点的时候,需要把头指针也制空。if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{//找尾SLTNode* cur = *pphead;SLTNode* prev = *pphead;while (cur->next != NULL){//cur下一个是NULL说明现在的这个就是尾prev = cur;cur = cur->next;}//产生野指针的问题,确实释放了但是我们cur的前面一个指向的是一个野指针。free(cur);prev->next = NULL;}
}SLTNode* SLTFind(SLTNode* phead, STLDatatype x)
{assert(phead);SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}
}// 在pos之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, STLDatatype x)
{SLTNode* newnode = BuySListNode(x);if (pos == *pphead){SLTpushfront(pphead, x);}else{SLTNode* cur = *pphead;while (cur->next!=pos){cur=cur->next;}cur->next = newnode;newnode->next = pos;}
}// 在pos以后插入x
void SLTInsertAfter(SLTNode* pos, STLDatatype x)
{SLTNode* newnode = BuySListNode(x);SLTNode* next = pos->next;pos->next = newnode;newnode->next = next;
}// 删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos)
{if (pos == *pphead){//头删SLTpopfront(pphead);}else{SLTNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}SLTNode* newhead = cur->next->next;free(pos);pos = NULL;cur->next = newhead;}
}// 删除pos的后一个位置
void SLTEraseAfter(SLTNode* pos)
{assert(pos->next != NULL);if (pos->next->next == NULL){free(pos->next);pos->next = NULL;pos->next = NULL;}else{SLTNode* next = pos->next->next;free(pos->next);pos->next = NULL;pos->next = next;}}// 单链表的销毁
void SListDestroy(SLTNode** plist)
{assert(plist != NULL);//只需要释放不需要改变,所以一级就可以SLTNode* cur = *plist;while (cur->next!=NULL){SLTNode* next = cur->next;cur->next = NULL;free(cur);cur = NULL;cur = next;SLTprint(cur);}cur->next = NULL;free(cur);cur = NULL;//原来的节点地址被释放,随机值但不是NULL*plist = NULL;
}

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

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

相关文章

C语言每天一练----输出水仙花数

题目&#xff1a;请输出所有的"水仙花数" 题解&#xff1a;所谓"水仙花数"是指一个3位数,其各位数字立方和等于该数本身。 例如, 153是水仙花数, 因为153 1 * 1 * 1 5 * 5 * 5 3 * 3 * 3" #define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h&g…

【自动化运维】Ansible常见模块的运用

目录 一、Ansible简介二、Ansible安装部署2.1环境准备 三、ansible 命令行模块3.1&#xff0e;command 模块3.2&#xff0e;shell 模块3.3&#xff0e;cron 模块3.4&#xff0e;user 模块3.5&#xff0e;group 模块3.6&#xff0e;copy 模块3.7&#xff0e;file 模块8&#xff…

【雕爷学编程】MicroPython动手做(10)——零基础学MaixPy之神经网络KPU

早上百度搜“神经网络KPU”&#xff0c;查到与非网的一篇文章《一文读懂APU/BPU/CPU/DPU/EPU/FPU/GPU等处理器》&#xff0c;介绍各种处理器非常详细&#xff0c;关于“KPU”的内容如下&#xff1a; KPU Knowledge Processing Unit。 嘉楠耘智&#xff08;canaan&#xff09;号…

找不到mfc140u.dll怎么解决

第一&#xff1a;mfc140u.dll有什么用途&#xff1f; mfc140u.dll是Windows操作系统中的一个动态链接库文件&#xff0c;它是Microsoft Foundation Class (MFC)库的一部分。MFC是 C中的一个框架&#xff0c;用于构建Windows应用程序的用户界面和功能。mfc140u.dll包含了MFC库中…

杂谈项——关于我在bw上的见闻,以及个人对二次元游戏行业方面的前瞻

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;今天为大家带来一点不一样的&#xff0c;首先先光速叠一下甲&#xff1a; 在此说明博主并不是一个什么都知道的大佬&#xff0c;只是一个普通的老二次元以及期望以后能…

HCIP重发布实验

目录 实验要求&#xff1a; 步骤一&#xff1a;拓扑设计IP地址规划 拓扑设计 R1 R2 R3 R4 发布路由 R1 R2 R3 R4 双向重发布 在R2和R4 上进行 R2 R4 检查R1 修改开销值选路 择优选择去4.0网段的路径 测试&#xff1a;​编辑 择优选择去32网段的路径 测试&…

短视频矩阵源码/系统搭建/源码

一、短视频矩阵系统开发需要具备以下能力 短视频技术能力&#xff1a;开发人员应具备短视频相关技术能力&#xff0c;如视频编解码、视频流媒体传输等。 大数据存储和处理能力&#xff1a;短视频矩阵系统需要处理大量的视频数据&#xff0c;因此需要具备大数据存储和处理的能力…

JavaScript快速入门:ComPDFKit PDF SDK 快速构建 Web端 PDF阅读器

JavaScript快速入门&#xff1a;ComPDFKit PDF SDK 快速构建 Web端 PDF阅读器 在当今丰富的网络环境中&#xff0c;处理 PDF 文档已成为企业和开发人员的必需品。ComPDFKit 是一款支持 Web 平台并且功能强大的 PDF SDK&#xff0c;开发人员可以利用它创建 PDF 查看器和编辑器&…

初探webAssembly | 京东物流技术团队

1 WebAssembly是什么&#xff1f; 一种运行在现代网络浏览器中的新型代码&#xff0c;并且提供新的性能特性和效果 W3C WebAssembly Community Group开发的一项网络标准&#xff0c;对于浏览器而言&#xff0c;WebAssembly 提供了一条途径&#xff0c;让各种语言编写的代码以接…

【Visual Studio】VS调用tensorflow C++API的配置(无需编译)

windows利用vs2015调用tensorflow c api 1. 首先下载并安装visual studio Visual Studio 2015 安装教程&#xff08;附安装包&#xff09;&#xff0c;按照博客中顺序来就可以 如果在安装过程中提示安装包丢失或损坏&#xff0c;参考VS2015安装过程中安装包丢失或损坏解决办…

策略模式的实现与应用:掌握灵活算法切换的技巧

文章目录 常用的设计模式有以下几种&#xff1a;一.创建型模式&#xff08;Creational Patterns&#xff09;&#xff1a;二.结构型模式&#xff08;Structural Patterns&#xff09;&#xff1a;三.行为型模式&#xff08;Behavioral Patterns&#xff09;&#xff1a;四.并发…

Spring注解系列——@PropertySource

在Spring框架中PropertySource注解是非常常用的一个注解&#xff0c;其主要作用是将外部化配置解析成key-value键值对"存入"Spring容器的Environment环境中&#xff0c;以便在Spring应用中可以通过Value或者占位符${key}的形式来使用这些配置。 使用案列 // Propert…

基于Citespace、vosviewer、R语言的文献计量学可视化分析及SCI论文高效写作方法教程

详情点击链接&#xff1a;基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法 前言 文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量…

工业边缘计算为什么?

在工厂环境中使用边缘计算并不新鲜。可编程逻辑控制器&#xff08;PLC&#xff09;、微控制器、服务器和PC进行本地数据处理&#xff0c;甚至是微型数据中心都是边缘技术&#xff0c;已经在工厂系统中存在了几十年。在车间里看到的看板系统&#xff0c;打卡系统&#xff0c;历史…

Flowable中间事件-中间信号捕获事件

定义 信号中间事件分为 Catching 事件和 Throwing 事件&#xff0c;即信号中间捕获事件&#xff08;Signal Intermediate Catch Event&#xff09;和信号中间抛出事件&#xff08;Signal Intermediate Throwing Event&#xff09;。 当流程执行到信号中间捕获事件时就会中断在…

什么是ROC曲线

ROC曲线&#xff08;Receiver Operating Characteristic Curve&#xff09;&#xff0c;也称为“接受者操作特性曲线”。它最早应用于雷达信号检测的分析&#xff0c;后来广泛应用于心理学和医学领域。 ROC分析是进行临床诊断试验评价最常用的方法。诊断试验是指评价某种疾病诊…

Xshell配置ssh免密码登录-公钥与私钥登录linux服务器

目录 简介 提示 方法步骤 步骤1&#xff1a;生成密钥公钥&#xff08;Public key&#xff09;与私钥(Private Key) 方法1&#xff1a;使用xshell工具 方法2&#xff1a;使用命令行 步骤2&#xff1a;放置公钥(Public Key)到服务器 方法1&#xff1a;&#xff08;我使用的是…

InnoDB数据存储结构

一. InnoDB的数据存储结构&#xff1a;页 索引是在存储引擎中实现的&#xff0c;MySQL服务器上的存储引擎负责对表中数据的读取和写入工作。不同存储引擎中存放的格式一般不同的&#xff0c;甚至有的存储引擎比如Memory都不用磁盘来存储数据&#xff0c;这里讲讲InooDB存储引擎…

NineData支持最受欢迎数据库PostgreSQL

根据在 Stack Overflow 发布的 2023 开发者调研报告中显示&#xff0c;PostgreSQL 以 45% vs 41% 的受欢迎比率战胜 MySQL&#xff0c;成为新的最受欢迎的数据库。NineData 也在近期支持了 PostgreSQL&#xff0c;用户可以在 NineData 平台上进行创建数据库/Schema、管理用户与…

解决AttributeError: ‘DataParallel‘ object has no attribute ‘xxxx_fc1‘

问题描述 训练模型时&#xff0c;分阶段训练&#xff0c;第二阶段加载第一阶段训练好的模型的参数&#xff0c;接着训练 第一阶段训练&#xff0c;含有代码 if (train_on_gpu):if torch.cuda.device_count() > 1:net nn.DataParallel(net)net net.to(device)第二阶段训练…