数据结构——单链表详解(超详细)(1)
前言:
小编在近日学习了单链表的知识,为了加强记忆,于是诞生了这一篇文章,单链表是数据结构比较重要的知识,读者朋友们一定要去好好的学习!这个可以说是比顺序表更好用的线性表,下面废话不多说,开始进入单链表的学习喽!
目录:
1.单链表
1.1.链表的概念与单链表
1.2.单链表的结构
1.3.单链表的性质
2.单链表功能的代码实现
2.1.单链表的打印
2.2.单链表的尾插
2.3.单链表的头插
2.4.单链表的尾删
2.5.单链表的头删
3.还有一些函数没写,由于小编不想让篇幅太大,所以分成了两部分
正文:
1.单链表
1.1.链表的概念
链表是一种物理结构上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表也有很多的种类,比如单链表,双链表等等,小编今天讲述的就是单链表,下面小编来讲述一下单链表的结构!
1.2.单链表的结构
引例:
对于单链表的结构,小编先给出一个引例:火车我相信各位读者朋友都坐过,没坐过也应该见过,火车是由车头和一节一节的车厢组成,如下图所示:
在人们乘车少的时候,火车可以减少车厢,具体减少哪个车厢,这是可以随机指出的,并不一定就是去掉最后一个车厢,我们也可以把中间的给删除,在旅游旺季的时候,我们同样也可以加上几节车厢来应对人多车少的情况。
1.2.1.结点的概念
单链表就类似火车车厢一样,它也可以随时的减少,随时的增加,我们把单链表中的每一表称之为结点,所以可以这么说,单链表是由一个一个结点构成的,单链表和顺序表最大的不同,就是单链表当中的结点是一个一个动态内存申请出来的,不是和顺序表一样基于数组来进行书写的,下面小编将会给各位讲述一下单链表的结构:
·1.2.2.单链表的结构
小编在上图给各位读者朋友了单链表的结构图,细细一看,我们可以看出每一个结点,里面都存储着数据类型和一个地址,不难发现,结点里面的地址都对应着下一个结点,所以单链表就是靠地址来进行连接的,那么肯定有读者朋友会感到疑惑,这么一看,单链表的物理结构不还是连续的?其实这个说法是错误的,可能每一个单链表都隔着很远才进行的链接,所以单链表是不连续的,不和顺序表的一样,我们可以看到,单链表中最后一个结点指向的是NULL,这里展示了单链表也是有始有终的,下面我们来简单介绍一下单链表的性质
1.3.单链表的性质
单链表的性质可以分为三个:
1.单链表在逻辑上是连续的(线性表统一的性质)在物理结构是不连续的。
2.结点一般都是从堆上申请的。
3.从堆上申请的空间,是按照一定策略分配出来的,每次申请的空间可能连续,也可能不连续
其实性质我们用多了,自然也会记住了,对于编程的学习,我们不是靠死记硬背下来的,而是不断的去应用,应用多了自然就熟悉了!
我们已经讲述了单链表的概念和性质,我们可不能纸上谈兵,下面,小编将带着大家手动的一步一步的去实现单链表!
2.单链表功能的代码实现
在讲述那些单链表的增删查改之前,我们现在肯定要先创建一个单链表,我们已经学习了顺序表和单链表的知识,单链表的结构图也在上面进行展示了,那么下面我们就可以实现单链表的创建了,对于数据部分,我们不一定是存储整型,浮点型等等,所以我们可以类似顺序表用typedef关键字来对类型改名,后面我们可以统一进行替换。下面是代码的实现:
typedef int SLdate; //方便后面整体类型的改变//创立一个单链表
typedef struct Slist {//先设置一个类型SLdate date;struct Slist* next; //存放下一个节点的地址
}SLTNode;
此外,对于单链表代码的书写,小编同样是分成了三个文件,与顺序表一样,这三个文件分别是头文件(用于单链表的创建,各种函数的声明),源文件(函数的实现),源文件(代码的测试),我们每写完一个函数,一定一定记着先测试,免得到后面在慢慢改,这样显得太麻烦了,下面,我们开始实现一一函数的功能!
2.1.单链表的打印
虽然我们还没有开始放置数据,但我们一定要先学会单链表的打印,这个与我们正常的打印是不同的! 首先,我们肯定要创建一个函数,下面是代码呈现:
void SLTprintf(SLTNode* phead);//此时phead代表的是头节点,就是第一个节点
正如代码解释所说,phead属于头结点,我们想要打印每一个结点的数据,肯定要先知道它的头节点,之后我们可以通过它的头结点来开始对下一个节点进行遍历直到遇到NULL,这样我们便可以停止打印,所以不难想到,这里我们用到了循环的知识,通过每一次循环来打印数据,之后再让下一个结点代替当前结点,不过在这之前,我们应该做到对于头结点不让它做出改变,因为我们倘若任由头节点进行改变,那么之后我们在这个函数中会再也不会找到链表的头,这样就得不偿失了,所以我们用一个新的结点来存放头节点,让它做出对应的的改变,下面是代码的呈现:
void SLTprintf(SLTNode* phead)
{SLTNode* pour = phead; //这么做是为了保证头节点不会发生改变while (pour){printf("%d->", pour->date);pour = pour->next;}printf("NULL\n");
} //这个操作是打印单链表的数据
2.2.单链表的尾插
我们在简述完打印后,肯定要讲述单链表的增删查改了,我们先从单链表的尾插说起,对于单链表的尾插,这其实和顺序表的尾插有点类似的,不过在顺序表中,在顺序表中,我们是扩容操作,而在单链表中,我们实现的是插入结点操作,在插入结点之前,我们是肯定先要创建一个新的结点,作为我们要插入的结点,不过我们在实现尾插之前,肯定是要先创建一个函数的,这里有我们值得注意的一个点,那就是我们传过去的应该是单链表指针的地址,也就是传一个二级指针过去,这是一个重要的点,因为我们要对单链表指针进行改变,对于内容的改变我们需要传址调用来实现,下面是函数的创建:
void SLTPushBack(SLTNode** pphead, SLdate x);
首先,我们需要先分装出一个函数,用来作为新结点的创建,这里我们需要用到malloc函数来对开辟出一个新的空间来作为新节点空间,之后我们再将数据转化为我们想要的数据,再让下一个结点置为空就好,这个操作可以类似于顺序表的扩容操作,下面是代码实现:
SLTNode* SLTbuynode(SLdate x)
{SLTNode* pour = (SLTNode*)malloc(sizeof(SLTNode));assert(pour);pour->date = x;pour->next = NULL;return pour;
}
之后我们就开始进行插入操作,这里我们分为两种情况:
第一种情况是头节点为空,这个就很简单了,我们将新节点的内容直接给予头节点就好了,这对于屏幕前的你当然是小case,尾插的大头就是下一个情况了:
第二种情况就是头节点不为空,正式进行尾插操作,这个操作其实是蛮简单的,我们只需要先进行循环,找到尾结点,让尾结点的next指针指向新结点就好了,下面我们用图文进行解释(这里用pcur当作尾结点!):
这样我们便可以实现尾插操作,下面是代码实现:
void SLTPushBack(SLTNode** pphead, SLdate x)
{//首先可以先建一个函数,这个函数是来开辟一个新节点的(后面想要插入直接调用就好了)assert(pphead);SLTNode * p = SLTbuynode(x);if (*pphead == NULL) //首先判断{*pphead = p;}else{SLTNode* pour = *pphead; //保证头节点不做出改变while (pour -> next){pour = pour->next;}pour->next = p;}
}
2.3.单链表的头插
//头插
void SLTPushFront(SLTNode** pphead, SLdate x);
我们在看完尾插操作以后,紧接着头插就来了,同样的,头插函数也需要先有一个新的结点的建立去,小编在上面已经叙述了,就不再多谢了,同样的,头插也同样分为了两种情况:
第一种情况是是头结点是不存在的,这时候只需要将新节点设置为头节点就好了。
第二种情况是头节点是存在的,这时候需要我们将新节点的下一个结点指向为原来的头节点,再将头节点更改为新节点就好了。具体情况小编用图文进行解释:
不过此时不难看拿出,头插函数似乎是不需要分两种情况讨论的,因为两种情况都涉及了将新节点的下一个结点变为头节点,所以我们将两种情况合并下来就好了,下面是代码呈现:
void SLTPushFront(SLTNode** pphead, SLdate x)
{assert(pphead);SLTNode* newnode = SLTbuynode(x);newnode->next = *pphead;*pphead = newnode;
}
2.3.单链表的尾删
//尾删
void SLTPopBack(SLTNode** pphead);
简单的插入函数就先告一段落了,下面我们来进行删除操作,首先登场的就是尾删,尾删操作,与顺序表的尾删一个概念,就是把单链表的尾结点置为空,首先,我们需要保证头节点是存在的,不然单链表都是空的,我们删来删去也没什么意思了,这里可以用assert断言来判断下头节点是否为空,之后我们就可以进行删除操作·。
首先,我们要先定义两个指针一个指向头节点,这个的作用是找到尾结点,一个为空(这个的作用我们稍后就知道),之后我们采用循环,让空指针在刚开始指向第一个指针,再让第一个指针一直往后走,我们是要找到尾结点,所以我们循环结束的条件就是第一个指针的下一个结点不指向空,之后第一个指针变成了尾结点,第二个指针变成了尾结点之前的结点,这样,我们就可以让第二个指针的下一个置为空,然后再让第一个指针释放掉,这样我们就完成了尾删操作,不过此时,细心的读者朋友可能会发现,如果单链表只有头节点的话,这时候上面就不成立了,我们这里就对空指针进行解引用了,所以尾删操作,我们同样也是分为两种情况!:
第一种是如果只有头节点的话,我们直接将头节点变为空,这里就完成了尾删操作。
第二种情况就是正常情况,方法就是上面所讲,下面是图文解释+代码呈现:
void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);if ((*pphead)->next == NULL){*pphead = NULL;}else{SLTNode* pour = *pphead;SLTNode* plist = NULL;while (pour->next){plist = pour;pour = pour->next;}plist->next = NULL;free(pour);pour = NULL;}
}
2.5.单链表的头删
尾删我们讲完了,下面是头删环节,与尾删一样,我们首先要判断头节点是否为空,如果为空直接报错就好了,之后我们就要进行正常的头删操作了,头删操作我们也要创建一个指针·,这个指针表示头节点,之后我们直接让现头节点变成原头节点的下一个结点,然后我们再将指针释放,这里我们便完成了单链表的头删操作,是不是很简单呢?下面小编给出图文解释和代码呈现:
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pour = *pphead;*pphead = (*pphead)->next;free(pour);pour = NULL;
}
总结:
正如小编上面所说,小编不想让文章的篇幅太大,于是小编就把博客分装成了两部分来进行书写,单链表的操作当然不仅限于这些了,下一篇将会是重点,如果文章有错误,恳请在评论区指出,小编肯定会改正,下面小编将要肝下篇文章了,那我们下一篇文章见喽!
相关文章:

数据结构——单链表详解(超详细)(1)
前言: 小编在近日学习了单链表的知识,为了加强记忆,于是诞生了这一篇文章,单链表是数据结构比较重要的知识,读者朋友们一定要去好好的学习!这个可以说是比顺序表更好用的线性表,下面废话不多说&…...
在 Linux 上使用 lspci 命令查看 PCI 总线硬件设备信息
lspci 命令用于显示 Linux 系统上的设备和驱动程序 当在个人电脑或服务器上运行 Linux 时,有时需要识别该系统中的硬件。lspci 命令用于显示连接到 PCI 总线的所有设备,从而满足上述需求。该命令由 pciutils 包提供,可用于各种基于 Linux 和…...

python数据可视化(6)——绘制散点图
课程学习来源:b站up:【蚂蚁学python】 【课程链接:【【数据可视化】Python数据图表可视化入门到实战】】 【课程资料链接:【链接】】 Python绘制散点图查看BMI与保险费的关系 散点图: 用两组数据构成多个坐标点,考察…...

【人工智能】Transformers之Pipeline(二):自动语音识别(automatic-speech-recognition)
目录 一、引言 二、自动语音识别(automatic-speech-recognition) 2.1 概述 2.2 技术原理 2.2.1 whisper模型 2.2.2 Wav2vec 2.0模型 2.3 pipeline参数 2.3.1 pipeline对象实例化参数 2.3.2 pipeline对象使用参数…...

Mysql-错误处理: Found option without preceding group in config file
1、问题描述 安装MYSQL时,在cmd中“初始化”数据库时,输入命令: mysqld --initialize --consolecmd报错: D:\mysql-5.7.36-winx64\bin>mysql --initialize --console mysql: [ERROR] Found option without preceding group …...

[iOS]内存分区
[iOS]内存分区 文章目录 [iOS]内存分区五大分区栈区堆区全局区常量区代码区验证内存使用注意事项总结 函数栈堆栈溢出栈的作用 参考博客 在iOS中,内存主要分为栈区、堆区、全局区、常量区、代码区五大区域 还记得OC是C的超类 所以C的内存分区也是一样的 iOS系统中&a…...
sklearn基础教程:掌握机器学习入门的钥匙
sklearn基础教程:掌握机器学习入门的钥匙 在数据科学和机器学习的广阔领域中,scikit-learn(简称sklearn)无疑是最受欢迎且功能强大的库之一。它提供了简单而高效的数据挖掘和数据分析工具,让研究人员、数据科学家以及…...

【unity实战】使用unity制作一个红点系统
前言 注意,本文是本人的学习笔记记录,这里先记录基本的代码,后面用到了再回来进行实现和整理 素材 https://assetstore.unity.com/packages/2d/gui/icons/2d-simple-ui-pack-218050 框架: RedPointSystem.cs using System.…...
开发指南046-机构树控件
为了简化编程,平台封装了很多前端组件。机构树就是常用的组件之一。 基本用法: import QlmOrgTree from /qlmcomponents/tree/QlmOrgTree <QlmOrgTree></QlmOrgTree> 功能: 根据权限和控制参数显示机构树。机构树数据来源于核…...

SpringBatch文件读写ItemWriter,ItemReader使用详解
SpringBatch文件读写ItemWriter,ItemReader使用详解 1. ItemReaders 和 ItemWriters1.1. ItemReader1.2. ItemWriter1.3. ItemProcessor 2.FlatFileItemReader 和 FlatFileItemWriter2.1.平面文件2.1.1. FieldSet 2.2. FlatFileItemReader2.3. FlatFileItemWriter 3…...
如何评估AI模型:评估指标的分类、方法及案例解析
如何评估AI模型:评估指标的分类、方法及案例解析 引言第一部分:评估指标的分类第二部分:评估指标的数学基础第三部分:评估指标的选择与应用第四部分:评估指标的局限性第五部分:案例研究第六部分:…...

程序员学CFA——经济学(七)
经济学(七) 汇率外汇市场外汇市场的功能外汇市场的参与者卖方买方 汇率的计算汇率报价基础货币与计价货币直接报价与间接报价外汇报价习惯 名义汇率和实际汇率货币的升值与贬值交叉汇率计算即期汇率与远期汇率即期汇率与远期汇率的概念远期升水/贴水远期…...

imx335帧率改到10fps的方法
验证: imx335.c驱动默认的帧率是30fps,要将 IMX335 的帧率更改为 10fps,需要调整与帧率相关的参数。FPS(frames per second,每秒帧数)通常由 sensor 的曝光时间(exposure time)和垂直总时间(VTS,Vertical Total Size)共同决定。VTS 定义了 sensor 完成一帧图像采集…...

Large Language Model系列之二:Transformers和预训练语言模型
Large Language Model系列之二:Transformers和预训练语言模型 1 Transformer模型 Transformer模型是一种基于自注意力机制的深度学习模型,它最初由Vaswani等人在2017年的论文《Attention Is All You Need》中提出,主要用于机器翻译任务。随…...

java后端项目启动失败,解决端口被占用问题
报错信息: Web server failed to start . Port 8020 was already in use. 1、查看端口号 netstat -ano | findstr 端口号 2、终止进程 taskkill /F /PID 进程ID 举例:关闭8020端口...

PostgreSQL安装/卸载(CentOS、Windows)
说明:PostgreSQL与MySQL一样,是一款开源免费的数据库技术,官方口号:The World’s Most Advanced Open Source Relational Database.(世界上最先进的开源关系数据库),本文介绍如何在Windows、Cen…...
OutOfMemoryError异常OOM排查
目录 参考工具MAT(Memory Analyzer)一、产生原因二、测试堆溢出 java.lang.OutOfMemoryError: Java heap space测试代码运行手动导出dump文件mat排查打开dump文件查看Leak Suspects(泄露疑点)参考 【JVM】八、OOM异常的模拟 MAT工具分析Dump文件(大对象定位) 用arthas排…...
【Python】Arcpy将excel点生成shp文件
根据excel点经纬度数据,生成shp,参考博主的代码,进行了修改,在属性表中保留excel中的数据。 参考资料:http://t.csdnimg.cn/OleyT 注意修改以下两句中的数字。 latitude float(row[1]) longitude float(row[2])imp…...

torch之从.datasets.CIFAR10解压出训练与测试图片 (附带网盘链接)
前言 从官网上下载的是长这个样子的 想看图片,咋办咧,看下面代码 import torch import torchvision import numpy as np import os import cv2 batch_size 50transform_predict torchvision.transforms.Compose([torchvision.transforms.ToTensor(),…...

什么ISP?什么是IAP?
做单片机开发的工程师经常会听到两个词:ISP和IAP,但新手往往对这两个概念不是很清楚,今天就来和大家聊聊什么是ISP,什么是IAP? 一、ISP ISP的全称是:In System Programming,即在系统编程&…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...