【数据结构】单链表的层层实现!! !

在这里插入图片描述
关注小庄 顿顿解馋(●’◡’●)

上篇回顾
我们上篇学习了本质为数组的数据结构—顺序表,顺序表支持下标随机访问而且高速缓存命中率高,然而可能造成空间的浪费,同时增加数据时多次移动会造成效率低下,那有什么解决之法呢?这就得引入我们链表这种数据结构

文章目录

  • 一.何为链表
    • 🏠 链表概念
    • 🏠 链表的分类![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6102a54bc82c4f25abb7816d1d2d0ebc.png)
  • 二.单链表的实现
    • 🏠 链表的打印
    • 🏠 链表的头插和尾插
    • 🏠 链表的尾删和头删
    • 🏠 链表指定位置的插入和删除
    • 🏠 链表的查找
    • 🏠 链表的销毁
    • `注: 这里要保存好下一个结点地址,销毁后就能继续遍历`
  • 三.单链表的分析以及与顺序表的比较
    • 🏠 单链表的优缺点
    • 🏠 单链表与顺序表的比较

一.何为链表

🏠 链表概念

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

特点:物理结构不一定连续,逻辑结构连续
在这里插入图片描述
我们的链表结构类似我们的火车,有头有尾,中间每个结点被有序链接;与火车不同的是,链表的结点可能不是紧挨着的。

在这里插入图片描述

类似这样,我们可以得出:
1.每个结点由数据和下一结点地址两部分组成,而每个结点构成了一个链表。
2.每个结点保存的是下一个结点的地址,这样就能找到下一个结点,最后为空就停止
3.每个结点的地址不是连续的,可以体现出链表的物理结构不一定连续

注:我们的结点一般是在堆区开辟的,因为此时你在程序结束前不free就会一直存在这块空间,同时可根据需要灵活申请结点存数据。

这样我们就可以用一个结构体封装每个结点:

typedef int Datatype;
typedef struct ListNode
{Datatype x;struct ListNode* next;
}Node;

注: 这里我们可以用typedef来重命名我们要存储的数据类型,这样对于不同数据的操作我们只要改typedef即可。

🏠 链表的分类在这里插入图片描述

我们根据链表三个特点:1.带头不带头 2.单向还是双向 3.循环还是不循环 组合成了如上的8种链表
本篇博客,我们要实现的是单向不带头不循环链表(单链表),至于什么是带头,双向,循环我们下回双链表再进行讲解


二.单链表的实现

无头+单向+不循环链表的增删差改

🏠 链表的打印

  • 链表数据的打印

这个接口就很好的体现了结点结构保存指针的妙处了~

//链表的打印
void SLTPrint(Node* phead)
{asser(phead);Node* cur = phead;while (cur){printf("%d ", cur->x);cur = cur->next;}
}

🏠 链表的头插和尾插

  • 链表的尾插

在这里插入图片描述
对于链表的尾插要注意几个问题:1.申请新结点 2.链表是否为空

解决方法:1.对于链表为空,直接让申请的新节点作为头节点 2.对于不为空的链表,首先要找到尾结点,再进行插入 3.对于申请新节点,我们后续的头插也要使用我们可以封装成一个接口,同时结点在堆区申请,调用完接口就不会释放了。

//申请新节点
Node* BuyNode(Datatype x)
{Node* newnode = (Node*)malloc(sizeof(Node));if (newnode == NULL){perror("malloc failed");return;}newnode->next = NULL;newnode->x = x;return newnode;
}void SLTPushBack(Node** pphead, Datatype x)
{assert(pphead);//申请新节点Node* newnode = BuyNode(x);//链表为空if (NULL == *pphead){*pphead = newnode;return;}//链表不为空:1.找尾巴结点2.插入新节点Node* ptail = *pphead;while (ptail->next){ptail = ptail->next;}ptail->next = newnode;
}

思考:这里为什么传二级指针?如果不传二级指针呢?

void SLTNPushBack(Node* pphead, Datatype x)
{//申请新节点Node* newnode = BuyNode(x);//链表为空if (NULL == pphead){pphead = newnode;return;}//链表不为空:1.找尾巴结点2.插入Node* ptail = pphead;while (ptail->next){ptail = ptail->next;}ptail->next = newnode;
}
int main()
{Node* n1 = NULL;SLTNPushBack(n1,1);return 0;
}

在这里插入图片描述
经过观察传一级指针版本的调用前后,我们发现n1这个指针变量存储的值并没发生改变,究其原因如下图
在这里插入图片描述

  • 链表的头插
    ,在这里插入图片描述
    *对于链表的头插要注意的问题:1.申请新节点 2.链表释放为空 *

解决方法:1.链表为空时,申请的新结点作为头结点 2.链表不为空时,让newnode->next指向原来头节点,再让newnode成为新的头节点。

void SLTPushFront(Node** pphead, Datatype x)
{assert(pphead);//申请新节点Node* newnode = BuyNode(x);//链表为空if (NULL == *pphead){*pphead = newnode;return;}newnode->next = *pphead;*pphead = newnode;
}

🏠 链表的尾删和头删

  • 链表的尾删
    在这里插入图片描述
    对于链表的尾删,我们需要分三种情况!

1.链表为空时此时删不了直接退出
2.链表只有一个结点时,释放头节点,置phead为空
3.链表有多个结点时,我们需要遍历链表找到尾结点的前置结点,先释放尾节点再将前置结点的next置为空
注:不能先将前置结点的next置为空,再释放尾结点,此时就找不到尾结点的地址了。

//链表的尾删和头删
void SLTPopBack(Node** pphead)
{assert(pphead);assert(*pphead);//判断链表不为空if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}Node* pre = *pphead;while (pre->next->next){pre = pre->next;}free(pre->next);pre->next = NULL;
}
  • 链表的头删

在这里插入图片描述
对于链表的头删,分为两种情况就可以了,因为有了phead很方便~

1.链表为空时,删不了直接断言下
2.链表不为空时,记录头节点的下一个位置,先释放头节点,再更换phead指向的位置

注:这里也不能先更新phead再释放头结点

void SLTPopFront(Node** pphead)
{assert(pphead);assert(*pphead);Node* pNext = (*pphead)->next;free(*pphead);*pphead = pNext;
}

🏠 链表指定位置的插入和删除

在这里插入图片描述

1.链表为空时,无法插入
2.pos位置结点刚好是头结点,直接头插或头删
3.pos位置结点不是头节点,需要找到pos位置的前置结点,记录位置。

void NodeInpos(Node** pphead, Node* pos, Datatype x)
{assert(pphead);//pos不为空 -》 链表一定不能为空assert(pos);assert(*pphead);//建立一个新节点Node* newnode = BuyNode(x);//pos刚好是头结点的情况if (*pphead == pos){//运用头插NodeinFront(pphead,x);return;}//pos刚好不是头结点//1.先找出pos前面的结点pre  2.newnode->next = pre->next 3.pre-<next = newnodeNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}newnode->next = pre->next;pre->next = newnode;
}void NodeDelpos(Node** pphead, Node* pos)
{assert(pphead);assert(pos);assert(*pphead);//pos刚好是第一个结点 执行头删if (*pphead == pos){NodeDelFront(pphead);return;}//pos不是第一个结点 1.先找到那个pos前面结点pre 2.pre->next = pos->next 3.freeNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}pre->next = pos->next;free(pos);pos = NULL;
}

🏠 链表的查找

Node* NodeFind(Node** phead, Datatype x)
{assert(phead);//遍历链表Node* pcur = *phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}//找不到则返回NULL
}

这里建议用一个临时变量来遍历~

🏠 链表的销毁

void NodeDestroy(Node** pphead)
{assert(pphead);assert(*pphead);//1.创一个临时变量存pcur->next的地址Node* pcur = *pphead;while (pcur){Node* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

注: 这里要保存好下一个结点地址,销毁后就能继续遍历

三.单链表的分析以及与顺序表的比较

🏠 单链表的优缺点

通过实现我们的单链表,我们发现单链表有以下优点

1.单链表不存在空间浪费(根据需求灵活在堆上申请新结点)
2.单链表的任意插入和删除效率高
(分析: 这里是已经确定插入的位置,对于链表只需改变指针的指向就能实现插入和删除,时间复杂度是O(1),而数组插入和删除需要遍历数组,时间复杂度是O(N)

单链表也不是万能的,它在一些应用场景也发挥不出来作用

1.不支持随机访问
2.缓存命中率低
3.查找效率低

总结:链表适用于频繁任意插入和删除的场景,不适用于随机访问和查找

🏠 单链表与顺序表的比较

单链表顺序表
物理空间不一定连续物理空间一定连续
不支持随机访问支持下标随机访问
插入和删除效率高 O(1)插入和删除效率低 O(N)
缓存命中率低缓存命中率高
无空间的浪费可能造成数据丢失和空间浪费
缓存利用率高

综上 我们可以根据场景需求选择不同的结构,灵活运用数据~


本次分享到这结束了,下篇我们将讲解双向链表,不妨来个一键三连捏

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

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

相关文章

VS Code引入ECharts

Charts是一个使用 JavaScript 实现的开源可视化库&#xff0c;涵盖各行业图表&#xff0c;提供了丰富的图表类型和交互能力。&#xff08;摘自菜鸟教程&#xff09; 下面我们来介绍一下VS Code引入ECharts的相关操作 检查电脑是否已经安装了Java语言的软件开发工具包 ECharts…

设计模式-行为型设计模式-命令模式

命令模式&#xff08;Command&#xff09;&#xff0c;将一个请求封装为一个对象&#xff0c;从而使你可用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。[DP] // 命令接口 interface Command {void execute(); }// 具体命…

备考银行科技岗刷题笔记(持续更新版)

银行考试计算机部分复习 IEEE 802.11的帧格式 1.1 IEEE 802.11是什么&#xff1f; 802.11是国际电工电子工程学会&#xff08;IEEE&#xff09;为无线局域网络制定的标准。目前在802.11的基础上开发出了802.11a、802.11b、802.11g、802.11n、802.11ac。并且为了保证802.11更…

java SSM售后服务管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

源码特点 java SSM售后服务管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采用B/…

Scrapy与分布式开发(2.3):lxml+xpath基本指令和提取方法详解

lxmlxpath基本指令和提取方法详解 一、XPath简介 XPath&#xff0c;全称为XML Path Language&#xff0c;是一种在XML文档中查找信息的语言。它允许用户通过简单的路径表达式在XML文档中进行导航。XPath不仅适用于XML&#xff0c;还常用于处理HTML文档。 二、基本指令和提取…

自编C++题目——几点了 hard ver.

题目难度 普及- 题目描述 一个老外用一口不流利的中文问你&#xff1a;“Xian zai ji dian le?”你看了一眼表&#xff0c;知道了现在是&#xff0c;你准备用这样的形式写在纸上&#xff1a; Now is m past/to h. 如果你看不懂&#xff0c;举个例子&#xff1a; 当h10&…

Rollup Summer:一览 Rollup 生态全景图

作者&#xff1a;Stanley&#xff0c;Kernel Ventures 编译&#xff1a;JIN&#xff0c;Techub News 短短几天内&#xff0c;ZKFair 的总锁定价值&#xff08;TVL&#xff09;已达到 1.2 亿美元&#xff0c;目前稳定在 8000 万美元&#xff0c;使其成为增长最快的 Rollup 之一…

SHARE 100M PRO:航测领域的多面手

在无人机航测领域&#xff0c;SHARE 100M PRO单镜头航测相机以其1.02亿像素的中画幅传感器和创新技术&#xff0c;正在重塑倾斜摄影的精度和效率。这款相机不仅在城市规划和土地管理中发挥着重要作用&#xff0c;还在环境监测、基础设施建设、农业管理等多个航测领域展现出其卓…

sheng的学习笔记-AI-多分类学习:ECOC,softmax

目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 基本术语&#xff1a; 若我们欲预测的是离散值&#xff0c;例如“好瓜”“坏瓜”&#xff0c;此类学习任务称为“分类”(classification)&#xff1b; 若欲预测的是连续值&#xff0c;例如西瓜成熟度0.95、0.37&#xff0c;…

软考69-上午题-【面向对象技术2-UML】-关系

一、关系 UML中有4种关系&#xff1a; 依赖&#xff1b;关联&#xff1b;泛化&#xff1b;实现。 1-1、依赖 行为&#xff08;参数&#xff09;&#xff0c;参数就是被依赖的事物&#xff0c;即&#xff1a;独立事物。 当独立事物发生变化时&#xff0c;依赖事务行为的语义也…

js【详解】原型 vs 原型链

原型 每个 class 都有显示原型 prototype每个实例都有隐式原型_proto_实例的_proto_指向对应 class 的 prototype 如下范例&#xff1a; class Student 创建了 实例 xialuo 获取属性 xialuo.name 或执行方法 xialuo.sayhi()时&#xff0c;先在自身属性和方法寻找&#xff0…

Visual Studio 2022 Version 17.9 新功能

Visual Studio 2022 v17.9 为广大 C 开发者引入了一系列好用的新功能和改进优化。 内存布局 现在&#xff0c;你可以使用【内存布局&#xff0c;Memory Layout】功能以可视化的方式来查看对象&#xff0c;结构体及联合体的内存布局信息&#xff0c;这可比以前需要手动查看内存…

CleanMyMac X4.15.0专为macOS设计的清理和优化工具

CleanMyMac X 是一款专为 macOS 设计的清理和优化工具。其基本功能和特点主要包括&#xff1a; 系统清理&#xff1a;CleanMyMac X 可以扫描并清除 macOS 系统中的垃圾文件&#xff0c;如缓存、日志、无用的语言文件等&#xff0c;从而释放硬盘空间并提高系统性能。应用程序管…

Tcp标志位 笔记240309

Tcp标志位 TCP&#xff08;传输控制协议&#xff09;的标志位是用于指示TCP报文段中特定控制信息的位字段。这些标志位存在于TCP报头中&#xff0c;用于控制TCP连接的建立、数据传输和终止等过程。以下是TCP标志位的详细说明&#xff1a; SYN&#xff08;同步标志&#xff09;…

python爬虫(3)

上一次的代码结果如下&#xff1a; 当然会有一点点不一样是正常的表现&#xff0c;因为这个图本身使用随机数rand函数做的&#xff0c;用其他两种随机函数出来的结果也不会完全相同。 继上节这次带来的是数组的重塑和转置 1、一维数组的重塑 在NumPy模块中的reshape()函数可…

【Vue+ElementUI】Table表格实现自定义表头展示+表头拖拽排序(附源码)

效果图 因项目采用的是Vue2&#xff0c;所以这个功能目前采用的是Vue2的写法。 Vue3请自行修改扩展代码&#xff1b;或收藏关注帖子&#xff0c;后续Vue3项目如有用到会在本帖子更新修改。 安装vuedraggable&#xff08;拖拽插件&#xff09; cnpm i vuedraggable先说用法&…

kafka查看消息两种方式(命令行和软件)+另附发送消息方式

1、命令行方式 ①找到kafka安装文件夹 ②执行命令 #指定offset为指定时间作为消息起始位置 kafka-consumer-groups.sh \ --bootstrap-server 20.2.246.116:9092 \ --group group_1 \ --topic lanxin_qiao \ --reset-offsets \ --to-datetime 2023-07-19T01:00:00.000 \ -exe…

MySQL-Linux安装

JDK安装&#xff08;linux版&#xff09; CentOS7环境&#xff1a; jdk下载地址huaweicloud.com 创建目录&#xff1a; mkdir /opt/jdk通过 ftp 客户端 上传 jdk压缩包&#xff08;linux版本&#xff09;到 1中目录进入目录&#xff1a;cd /opt/jdk解压&#xff1a;tar -zxv…

一篇了解电感的使用

一、电感理论基础 1.电感的定义 当电流通过线圈后&#xff0c;会产生磁场&#xff0c;磁感线穿过线圈&#xff0c;产生的磁通量与电流 i有如下关系&#xff1a; 将漆包线、纱包线或塑皮线等在绝缘骨架或磁心、铁心上绕制而成的器件&#xff0c;当线圈通过电流后&#xff0c;在…

linux应用程序需要编写的脚本

每一个程序都按照下面的要求进行脚本编写 多个应用之间联合安装采用编写外围脚本&#xff0c;依次调用多个应用的脚本的方式实现