【数据结构和算法初阶(C语言)】链表-单链表(手撕详讲单链表增删查改)

目录

1.前言:顺序表回顾:

1.1顺序表的优缺点 

2.主角----链表

2.1链表的概念

2.2定义一个单链表的具体实现代码方式

3.单链表对数据的管理----增删查改

3.1单链表的创建

3.2单链表的遍历实现

3.2.1利用遍历实现一个打印我们链表内容的函数的函数 

3.3头插法----从头部插入数据实现

3.4尾插法---从尾部插入数据

3.5尾删法-----从尾部删除数据

3.6头删法

3.7寻找函数 

3.8修改函数

3.9在pos位置前插入

3.10在pos位置后插入

3.11在pos位置前删除

3.12在pos位置后一个位置删除

3.13在pos位置删除

4.补充链表类型暂时了解 

5.结语 


1.前言:顺序表回顾:

顺序表知识回顾

1.1顺序表的优缺点 

  • 优点:

        1.尾插、尾删速度足够快

        2.可以使用下标来进行随机访问和数据修改

  • 缺点:

        1. 中间/头部的插入删除,时间复杂度为O(N)

        2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。比如我们realloc增添空间还会涉及到原始空间数据的拷贝和原始空间的释放。

        3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

               

为了解决单链表的这缺点,于是我们引入了链表,链表优点(可以按需申请空间

2.主角----链表

(今天重要讲解单链表),链表具有八种结构

2.1链表的概念

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

2.2单链表的结构演示

在数据结构中,我们往往会以创建结构体的方式来实现链表,在结构体中定义至少定义两个成员:一个保存我们当前节点的数据,我们称为数据域,另外一个成员保存下一个节点的地址,我们称为指针域

从上图,我们就可以发现,链式结构在逻辑上是连续的就是我们可以通过指针顺序找到链表中的每个节点但是,在物理上不一定连续,因为我们每一个节点的空间都是通过malloc在堆上申请开辟的空间,那么地址可能不连续。

2.2定义一个单链表的具体实现代码方式

typedef int SLTDataType;typedef struct SListNode
{SLTDataType  data;//数据领域struct SListNode* next;//定义指针领域,方便保存下一个节点的地址}SLNode;

为了后期使用方便,我把整型这个类型重新定义了一下,后续如果需要改变我们这个程序中的数据类型,比如换成doubble类型,我们换一下宏定义就好。

 

3.单链表对数据的管理----增删查改

3.1单链表的创建

有了结构体类型,那我们就可以创建一个单链表:

1.首先我们先创建一个节点,由于后续插入等等操作都要创建节点,这里我们就可以将节点创建过程分装为一个函数:

SLNode* BuySListNode(SLTDataType x)
{//首先为我们的节点申请空间,创建一个节点,就申请这个结构体类型那么大的一个空间就行SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));//判断一下是否开辟成功if (newnode == NULL){perror("malloc");exit(-1);}//开辟成功,就初始化这个节点newnode->data = x;newnode->next = NULL;return newnode;//返回节点地址
}

2.然后我们将每个节点链接起来,通个指针和每个节点的地址,这里就涉及头部插入数据和尾部插入数据,我们放在下面实现:

3.2单链表的遍历实现

3.2.1利用遍历实现一个打印我们链表内容的函数的函数 

void SLPrint(SLNode* phead)
{SLNode* cur = phead;while (cur){printf("%d ->", cur->data);cur = cur->next;//指针移动到下一个节点}printf("NULL");}

 

3.3头插法----从头部插入数据实现

首先,我们先定义准备一个头指针,用于保存我们链表第一个节点的地址,,方便我们后期使用整块链表。

然后,当我们还没有链表,这时候放入第一个节点:

我们把节点地址给我们的头指针就好。

2.当我们的头指针不为空,这时要插入数据

应该将第一个节点的地址赋值给newnode的next,然后将我们newnode节点作为我们的心的头结点将地址给头指针。

两种情况可以视为一种情况,只是第一种特殊一下,我们的头指针指向空。

注意:在我们写头插函数的时候,传递的是头指针的地址,我们在函数中解引用操作操作的是原先的指针,这样才能整体使用我们的空间,如果我们只是传指针,那么在我们的头插函数中的头指针,只是我们真正头指针的一份拷贝,这样函数结束,形参就销毁,虽然空间开辟了,但是调用结束我们使用的还是原来没插入前的空间。

void SListPushBack(SLNode** phead,int x)
{SLNode* newnode = BuySListNode(x);newnode->next = *phead;*phead = newnode;}

3.4尾插法---从尾部插入数据

 

当我们还没有链表,这时候放入第一个节点:

两种情况实现:

void SLTPushBack(SLNode** phead, SLTDataType x)
{SLNode* newnode = BuySListNode(x);//创建新节点if (*phead == NULL){newnode->next = *phead;*phead = newnode;}else{SLNode* cur =*phead;while (cur->next){cur = cur->next;}cur->next = newnode;}}

3.5尾删法-----从尾部删除数据

  • ①当我们没有链表此时没有删除的东西,所以不能传入空指针
  • ②当我们只有一个节点要删除

那么由于我们头指针有所改变,所以函数传参还是传递我们的头指针的地址

  • ③当有很多节点

尽量不用->next->next=NULl的形式做判断,当只有一个节点的时候越界访问。 

实现一下:
 

void SLTPopBack(SLNode** phead)
{assert(*phead);//头指针不能为空if ((*phead)->next == NULL){free(*phead);*phead = NULL;}else{SLNode* bfend = NULL;SLNode* end = *phead;while (end->next){bfend = end;end = end->next;}free(bfend->next);bfend->next = NULL;}
}

3.6头删法

void SLTPopFront(SLNode** phead)
{assert(*phead);//当头指针非空SLNode* newnode =(*phead)->next;(*phead)->next = NULL;free(*phead);*phead = newnode;
}

 

3.7寻找函数 

遍历寻找某个值

SLNode* SLFind(SLNode* phead, SLTDataType x)
{SLNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;}

3.8修改函数

找到值返回对应位置的指针,然后通过指针修改

void  SLMod(SLNode* phead)
{int x = 0;printf("请输入你要修改的值:\n");scanf("%d", &x);SLNode* ret = SLFind(phead, x);if (ret){printf("请输入你要修改成什么值\n");int c = 0;scanf("%d", &c);ret->data = c;}
}

3.9在pos位置前插入

涉及到头插,就要涉及头指针的改变,那么我们就要传二级指针:

void SLTInsert(SLNode** phead, SLNode* pos, SLTDataType x)
{//不能传入空指针assert(pos);if (pos == *phead)//头插{SListPushBack(phead, x);}else{//先遍历到要插入的位置前一个SLNode* pre = *phead;while (pre->next != pos){pre = pre->next;}//然后插入这个新节点,开辟新节点SLNode* newnode = BuySListNode(x);pre->next = newnode;newnode->next = pos;}
}

3.10在pos位置后插入

不是不能和头指针相等,是不能为空指针。不可能实现头插

void SLTInsertAfter(SLNode* pos, SLTDataType x)
{assert(pos);SLNode* newnode = BuySListNode(x);newnode->next = pos->next;pos->next = newnode;
}

 

3.11在pos位置前删除

3.12在pos位置后一个位置删除

void SLTEraseAfter(SLNode* pos)
{//不能传空指针、头指针、和指向尾节点的指针,没有意义assert(pos);assert(pos->next);SLNode* posNext = pos->next;pos->next = posNext->next;free(posNext);posNext = NULL;
}

3.13在pos位置删除

void SLTErase(SLNode** phead, SLNode* pos)
{assert(pos);//断言不会传入空指针if (pos == *phead){//头删SLTPopFront(phead);}else{SLNode* pre = *phead;while (pre->next != pos){pre - pre->next;}pre->next = pos->next;free(pos);pos = NULL;}
}

4.补充链表类型暂时了解 

① 单向或者双向

②带头或者不带头

③循环或者非循环

5.结语 

今天的重点在于理解单链表的增删查改,特别是什么时候需要传输二级指针,什么时候不传。以上就是本期的所有内容,知识含量蛮多,大家可以配合解释和原码运行理解。创作不易,大家如果觉得还可以的话,欢迎大家三连,有问题的地方欢迎大家指正,一起交流学习,一起成长,我是Nicn,正在c++方向前行的奋斗者,数据结构内容持续更新中,感谢大家的关注与喜欢。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【软件测试】--功能测试4-html介绍

1.1 前端三大核心 html:超文本标记语言&#xff0c;由一套标记标签组成 标签&#xff1a; 单标签&#xff1a;<标签名 /> 双标签:<标签名></标签名> 属性&#xff1a;描述某一特征 示例:<a 属性名"属性值"> 1.2 html骨架标签 <!DOC…

Java基础八股

基础概念与常识 Java 语言有哪些特点? 简单易学&#xff1b;面向对象&#xff08;封装&#xff0c;继承&#xff0c;多态&#xff09;&#xff1b;平台无关性&#xff08; Java 虚拟机实现平台无关性&#xff09;&#xff1b;支持多线程&#xff08; C 语言没有内置的多线程…

Ansible自动化运维(四)jinja2 模板、Roles角色详解

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

Retrofit核心原理

Retrofit是一个类型安全的HTTP客户端库&#xff0c;广泛用于Android和Java应用中&#xff0c;用于简化网络请求和响应的处理。本文将深入探讨Retrofit的核心原理&#xff0c;帮助开发者理解其背后的工作机制。 Retrofit简介 Retrofit是Square公司开发的一个开源库&#xff0c…

非线性优化资料整理

做课题看了一些非线性优化的资料&#xff0c;整理一下&#xff0c;以方便查看&#xff1a; 优化的中文博客 数值优化|笔记整理&#xff08;8&#xff09;——带约束优化&#xff1a;引入&#xff0c;梯度投影法 (附代码)QP求解器对比对于MPC的QP求解器 数值优化| 二次规划的…

Socket网络编程(一)——网络通信入门基本概念

目录 网络通信基本概念什么是网络&#xff1f;网络通信的基本架构什么是网络编程?7层网络模型-OSI模型什么是Socket&#xff1f;Socket的作用和组成Socket传输原理Socket与TCP、UDP的关系CS模型(Client-Server Application)报文段牛刀小试&#xff08;TCP消息发送与接收&#…

nebula容器方式安装:docker 安装nebula到windows

感谢阅读 基础环境安装安装docker下载nebula 安装数据库命令行安装查询network nebula-docker-compose_nebula-net并初始化查询安装初始使用root&#xff08;God用户类似LINUX的root&#xff09; 关闭服务 安装UI 基础环境安装 安装docker 点我下载docker 下载nebula 数据…

柯桥会计培训学校,会计职称考试,考中级会计怎么证明工作年限?

中级会计考试是会计从业人员的重要考试之一&#xff0c;对于中级考生来说&#xff0c;工作年限证明是必不可少的一步。因此&#xff0c;在考中级会计之前&#xff0c;需要对如何证明工作年限进行了解和掌握。 为大家整理了工作年限证明相关信息&#xff0c;一起来看看吧~ 一、…

手把手教你使用python中的循环for和while

python中的for循环是一个通用的序列迭代器&#xff0c;可以遍历任何有序的序列对象内部的元素&#xff0c;&#xff08;注意是遍历&#xff09;&#xff0c;也就是说循环的方式一开始就固定好了&#xff0c;本质上是遍历。 python&#xff1a;代码 count 0for i in range(8):…

挑战杯 基于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…

【代码解读】OpenCOOD框架之model模块(以PointPillarFCooper为例)

point_pillar_fcooper PointPillarFCooperPointPillarsPillarVFEPFNLayerPointPillarScatterBaseBEVBackboneDownsampleConvDoubleConv SpatialFusion检测头 &#xff08;紧扣PointPillarFCooper的框架结构&#xff0c;一点一点看代码&#xff09; PointPillarFCooper # -*- c…

Docker Volume

"Ice in my vein" Docker Volume(存储卷) 什么是存储卷? 存储卷就是: “将宿主机的本地文件系统中存在的某个目录&#xff0c;与容器内部的文件系统上的某一目录建立绑定关系”。 存储卷与容器本身的联合文件系统&#xff1f; 在宿主机上的这个与容器形成绑定关系…

js 常见报错 | js 获取数据类型 | js 判断是否是数组

文章目录 js 常见报错1.1 SyntaxError&#xff08;语法错误&#xff09;1.2 ReferenceError&#xff08;引用错误&#xff09;1.3 RangeError&#xff08;范围错误&#xff09;1.4 TypeError&#xff08;类型错误&#xff09;1.5 URLError&#xff08;URL错误&#xff09;1.6 手…

软考50-上午题-【数据库】-SQL访问控制

一、SQL访问控制 数据控制&#xff0c;控制的是用户对数据的存储权力&#xff0c;由DBA决定。 DBA&#xff1a;数据库管理员。 DBMS数据控制应该具有一下功能&#xff1a; 1-1、授权语句格式 说明&#xff1a; 示例&#xff1a; 1-2、收回权限语句格式 示例&#xff1a; PUBLI…

海外社媒营销:动态住宅代理IP的妙用

动态代理IP&#xff0c;顾名思义&#xff0c;是一种可以动态变化的IP地址。与传统的静态IP地址不同&#xff0c;动态代理IP在每次网络请求时都能提供一个新的IP地址。在进行海外推广活动时&#xff0c;它的应用非常关键。 动态代理IP的工作原理基于一个庞大的IP地址池。当用户…

Unity中字符串拼接0GC方案

本文主要分析C#字符串拼接产生GC的原因&#xff0c;以及介绍名为ZString的库&#xff0c;它可以将字符串生成的内存分配为零。 在C#中&#xff0c;字符串拼接通常有三种方式&#xff1a; 直接使用号连接&#xff1b;string.format;使用StringBuilder&#xff1b; 下面分别细…

基于springboot的4S店车辆管理系统源码和论文

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

使用 gregwar/captcha 生成固定字符的验证码

图片验证码生成失败 $captcha new CaptchaBuilder("58 ?"); $code $captcha->getPhrase();\Cache::put($key, [phone > $phone, code > $captcha->getPhrase()], $expiredAt);$captcha->build(); $result [captcha_key > $key,expired_at >…

海量物理刚体 高性能物理引擎Unity Physics和Havok Physics的简单性能对比

之前的博客中我们为了绕过ECS架构&#xff0c;相当于单独用Batch Renderer Group实现了一个精简版的Entities Graphics&#xff0c;又使用Jobs版RVO2实现了10w人同屏避障移动。 万人同屏对抗割草 性能测试 PC 手机端 性能表现 弹幕游戏 海量单位同屏渲染 锁敌 避障 非ECS 那么有…