数据结构初阶-单链表

news2024/9/19 15:18:33

        链表的结构非常多样,以下情况组合起来就有8种(2 x 2 x 2)链表结构:

        而我们主要要熟悉的单链表与双向链表的全称分别为:不带头单向不循环链表,带头双向循环链表,当我们对这两种链表熟悉后,便能不费力的推出另外四种链表。我们本文主要介绍单链表。

 一,单链表的概念与结构

1.1概念       

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

        这里我们可以联想平时我们所坐的高铁或火车,淡季时车次的车厢会相应减少,旺季时车次的车厢会额外增加几节。只需要将火车里的某节车厢去掉/ 加上,不会影响其他车厢,每节车厢都是独立存在的。

        那,在链表中我们的火车车厢又是怎么样的:

 1.2结点

        与顺序表不同的是,链表里的每节"车厢"都是独立申请下来的空间,我们称之为“结点/结点”。结点的组成主要有两个部分:当前结点要保存的数据和保存下⼀个结点的地址(指针变量)。

        图中指针变量 plist保存的是第⼀个结点的地址,我们称plist此时“指向”第⼀个结点,如果我们希望 plist“指向”第⼆个结点时,只需要修改plist保存的内容为0x00B0。

1.3链表的性质

1、链式机构在逻辑上是连续的,在物理结构上不⼀定连续

2、结点⼀般是从堆上申请的

3、从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

        结合前⾯学到的结构体知识,我们可以给出每个结点对应的结构体代码:(因为我们存储的数据类型不定,所以我们可以先将我们要存储的数据类型先定义下):

typedef int SLDataType;


typedef struct SLTistNode
{
	SLDataType Data;
	struct SLTistNode* next;
}SLTNode,*PSLTNode;

        当我们想要保存⼀个整型数据时,实际是向操作系统申请了⼀块内存,这个内存不仅要保存整型数据,也需要保存下⼀个结点的地址(当下⼀个结点为空时保存的地址为空)。

接下来让我们来实现单链表的常用功能,实现的功能大多与顺序表类似:

二,单链表功能的实现

2.1链表的初始化

        在介绍它的初始化之前,我们先来介绍什么是带头(哨兵位)和不带头,对于带头,则是链表头部初始时便有一个哨兵位节点,但不存放任何数据,由于我们的单链表为不带头链表,所以我们这里初始化直接引用上面的结构体,设置我们的链表头为空指针即可:

PSLTNode plist = NULL;

2.2获取新节点函数SLTBuyNode

       在对链表进行头尾插之前,由于我们每次插入节点都需要创建新的节点,所以我们则合理直接分装一个函数,后面实现头尾插功能直接调用即可,老样子,我们先给出代码:

PSLTNode SLTBuyNode(SLDataType x)
{
	PSLTNode node = (PSLTNode)malloc(sizeof(SLTNode));
	if (node == NULL)
	{
		perror("newnode:");
		exit(1);
	}
	node->Data = x;
	node->next = NULL;
	return node;
}

       由于我们的链表内存的大小是动态变化的,所以我们需要使用malloc函数来开辟节点的空间。为了确保我们代码的健壮性,我们需要检验空间开辟是否成功。然后将所需要插入的数据赋值给新节点的data,同时将新节点的next置为空。

2.3尾插函数SLTPushBack

       由于我们这里是在链表的尾端进行尾插,所以我们直接将当前的链表尾节点的指针设置为我们要创建的新节点的地址:

void SLTPushBack(PSLTNode* pphead, SLDataType x)
{
	assert(pphead);
	PSLTNode newcode = SLTBuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = newcode;
	}
	else
	{
		PSLTNode pcur = *pphead;
		while (pcur->next)
		{
			pcur = pcur->next;
		}
		pcur->next = newcode;
	}
}

        由于我们初次插入节点时,链表此时为空,所以我们在其为空时直接将指向新节点的指针设置为指向链表头节点的指针,但尾插我们需要遍历链表找到尾节点,所以时间复杂度为O(N)。

2.4头插函数SLTPushFront

       相对于尾插法,我们的头插法就简单许多,只需要将要插入的新节点的next指针直接设置为指向链表头节点的指针,然后再将头节点的指针设置为指向新节点的指针即可:

void SLTPushFront(PSLTNode* pphead, SLDataType x)
{
	assert(pphead);
	PSLTNode newcode = SLTBuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = newcode;
	}
	else
	{
		newcode->next = *pphead;
		*pphead = newcode;
	}
}

  我们可以明显的看到,头插法的方式没有遍历数组,它的时间复杂度为O(1)。

2.5尾删函数SLTPopBack 

       在进行尾删之前,我们需要判断链表中是否还有节点,如果没有节点,我们就不能再对链表进行删除:

void SLTPopBack(PSLTNode* pphead)
{
	assert(pphead && *pphead);
	PSLTNode pcur = *pphead;
	PSLTNode pcur1 = NULL;
	while (pcur->next)
	{
		pcur1 = pcur;
		pcur = pcur->next;
	}
	if (pcur1)
	{
		pcur1->next = NULL;
		free(pcur);
		pcur = NULL;
	}
	else
	{
		free(*pphead);
		*pphead = NULL;
	}
}

        首先我们要遍历链表找到尾节点,我们可以先对头节点的NEXT判空,如果为空,则说明链表中的节点只有一个,我们直接释放头节点即可。如果不为空,我们则直接循环找到尾节点,对其进行释放,同时将其上一个节点的NEXT置为空。

2.6头删函数SLTPopFront

         老样子,我们需要先判断链表是否还有节点,有直接先记住头节点的指针,然后让头指针指向它的NEXT即可:

void SLTPopFront(PSLTNode* pphead)
{
	assert(pphead && *pphead);
	PSLTNode pcur = *pphead;
	*pphead = pcur->next;
	free(pcur);
	pcur = NULL;
}

       我们在这里会发现,头删相比于尾删也简单很多,所以当我们在没有特殊要求的情况下,尽量使用头删/插对链表进行增删操作,这样复杂度会少很多。

2.7寻找指定节点函数SLTFind

       在实现删除/增加指定位置数据之前,由于这两个函数都需要寻找数据,所以我们可以直接将寻找函数分装为一个函数,便于我们后面直接调用:

PSLTNode SLTFind(PSLTNode phead, SLDataType x)
{
	assert(phead);
	PSLTNode pcur = phead;
	while (pcur)
	{
		if (pcur->Data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

       如果没有找到目标数据,我们直接返回空指针即可,同时我们需要遍历链表一个一个去寻找,这是我们常用的寻找方法。

2.8向指定位置之后插入数据函数SLTInsertAfter

       我们这里不介绍在之前插入数据的原因是因为此时我们需要遍历链表去找到指定位置前方的数据,所以复杂度会高很多,而这里我们删除指定位置之后则不需要遍历链表:

void SLTInsertAfter(PSLTNode pos, SLDataType x)
{
	assert(pos);
	PSLTNode newcode = SLTBuyNode(x);
	newcode->next = pos->next;
	pos->next = newcode;
}

需要注意的即是对NEXT指针指向的改变,实现难度不高。

2.9删除指定位置之后的数据函数SLTEraseAfter

 与之前的删除一样,我们需要先判断链表中是否有节点:

void SLTEraseAfter(PSLTNode pos)
{
	assert(pos && pos->next);
	PSLTNode del = pos->next;
	pos->next = pos->next->next;
	free(del);
	del = NULL;
}

  会了我们上面的头删与尾删函数之后,其实这部分很简单。

2.10链表的销毁函数SListDestroy 

void SListDestroy(PSLTNode* pphead)
{
	assert(pphead && *pphead);
	PSLTNode pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

这里我们也需要判断链表是否为空,如果为空我们也就没必要释放链表空间 。

三,几道单链表OJ题推荐

203. 移除链表元素 - 力扣(LeetCode)

206. 反转链表 - 力扣(LeetCode)

876. 链表的中间结点 - 力扣(LeetCode) 

21. 合并两个有序链表 - 力扣(LeetCode) 

链表分割_牛客题霸_牛客网 (nowcoder.com) 

链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 

160. 相交链表 - 力扣(LeetCode) 

141. 环形链表 - 力扣(LeetCode) 

142. 环形链表 II - 力扣(LeetCode) 

       这里尤其是最后两道,使用了Floyd龟兔赛跑算法,非常推荐去练习学习 ,下篇文章我们将介绍双向链表,同时介绍一下最后两道OJ题的思想方法。

       

 

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

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

相关文章

基于python深度学习遥感影像地物分类与目标识别、分割实践技术应用

目录 专题一、深度学习发展与机器学习 专题二、深度卷积网络基本原理 专题三、TensorFlow与Keras介绍与入门 专题四、PyTorch介绍与入门 专题五、卷积神经网络实践与遥感图像场景分类 专题六、深度学习与遥感图像检测 专题七、遥感图像检测案例 专题八、深度学习与遥感…

【教学类-68-01】20240720裙子涂色(女孩篇)

背景需求: 通义万相下载了简笔画裙子,制作成涂色卡给幼儿涂色、剪纸用。 代码展示 裙子简笔画图 6张 星火讯飞、通义万相、阿夏 2024年7月20日import os,time import shutil from docx import Document from docx.shared import Cm from PIL import Ima…

ApolloAndroid 使用笔记

由于业务需求的变化,需要使用 Graphql 作为客户端与服务端的交互查询框架,特此记录使用。 测试代码下载链接 一、导入引用以及规则示例 1、首先需要在我们需要使用的模块下面创建对应的src/main/graphql文件夹 2、将后台对应的服务生成的 xxx.graphql…

1个Xpath定位可以在Web页面查找到多个元素Selenium

1个Xpath定位可以在Web页面查找到多个元素Selenium//input[id\"transactionId\"] 打开Web页面, 点击F12可以看到压面 点击Ctrl F 可以点图如下图的输入框,输入xpath,看右侧可以找到3个对应的元素 点击Ctrl F 点击Ctrl F 点…

【C语言】逗号运算符详解 - 《不起眼的 “逗号”》

目录 C语言逗号运算符详解1. 逗号运算符的定义1.1 基本语法1.2 执行顺序 2. 逗号运算符的用法2.1 用于循环2.1.1 示例 2.2 用于表达式组合2.2.1 示例 3. 逗号运算符的应用场景3.1 宏定义3.1.1 示例 3.2 条件运算符中的应用3.2.1 示例 4. 总结5. 参考文献6. 结束语 C语言逗号运算…

通信网络机房服务器搬迁流程方案

数据中心机房搬迁是一项负责高难度的工程。整个搬迁过程充满挑战,伴随着各种风险。如何顺利的完成服务器的迁移,需要专业的数据中心服务商全程提供保障。友力科技(广州)有限公司,作为华南地区主流的数据中心服务商&…

Python代码,强化学习,深度学习

python代码编写,Python算法设计,强化学习优化,改进模型,训练模型,测试模型,可视化绘制,代编运行结果,交互多模型改进,预测模型,算法修改,Python包…

docker: No space left on device处理与迁移目录

简介:工作中当遇到Docker容器内部的磁盘空间已满。可能的原因包括日志文件过大、临时文件过多或者是Docker容器的存储卷已满,需要我们及时清理相关文件,并对docker的路径进行迁移。 历史攻略: centos:清理磁盘空间 …

三国杀十周年电脑版PC端模拟器游玩教程

三国杀十周年电脑版PC端模拟器游玩教程 《三国杀十周年》是一款以三国时代丰富的历史背景和独特的玩法手机策略游戏,在游戏中可自由选择扮演一位三国时期著名的人物,吸引了大量的历史爱好者和卡牌游戏玩家。如果大家想要轻松享受端游操作体验&#xff0…

【一刷《剑指Offer》】面试题 32:从 1 到 n 整数中 1 出现的次数

力扣对应题目链接:233. 数字 1 的个数 - 力扣(LeetCode) 牛客对应题目链接:整数中1出现的次数(从1到n整数中1出现的次数)_牛客题霸_牛客网 (nowcoder.com) 一、《剑指Offer》对应内容 二、分析题目 先随便…

Go语言之内存分配

文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ Go 语言程序所管理的虚拟内存空间会被分为两部分:堆内…

牛客TOP101:单链表的排序

文章目录 1. 题目描述2. 解题思路3. 代码实现 1. 题目描述 2. 解题思路 按我们以往的排序算法来看,针对链表来说都是太不合适,因为很多都会出现指针前移后移,后移还好说,前移对于链表来说就太难了,而且大部分都是某一个…

HiDiff: 用于医学图像分割的混合扩散框架| 文献速递-基于深度学习的多模态数据分析与生存分析

Title 题目 HiDiff: Hybrid Diffusion Framework for Medical Image Segmentation HiDiff: 用于医学图像分割的混合扩散框架 01 文献速递介绍 医学图像分割是将医学图像数据转化为有意义的、空间结构化的信息,如器官和肿瘤。随着深度学习(DL&#x…

primeflex教学笔记20240720, FastAPI+Vue3+PrimeVue前后端分离开发

练习 先实现基本的页面结构&#xff1a; 代码如下&#xff1a; <template><div class"flex p-3 bg-gray-100 gap-3"><div class"w-20rem h-12rem bg-indigo-200 flex justify-content-center align-items-center text-white text-5xl">…

RESTful API设计指南:构建高效、可扩展和易用的API

文章目录 引言一、RESTful API概述1.1 什么是RESTful API1.2 RESTful API的重要性 二、RESTful API的基本原则2.1 资源导向设计2.2 HTTP方法的正确使用 三、URL设计3.1 使用名词而非动词3.2 使用复数形式表示资源集合 四、请求和响应设计4.1 HTTP状态码4.2 响应格式4.2.1 响应实…

新能源汽车空调系统的四个工作过程

汽车空调制冷系统组成 1.汽车空调制冷系统组成 以R134a为制冷剂的汽车空调制冷系统主要包括压缩机、电磁离合器、冷凝器、 散热风扇、储液于燥器、膨胀阀、蒸发器、鼓风机、制冷连接管路、高低压检测 连接接头、调节与控制装置等组成。 汽车空调的四个过程 1压缩过程 传统车…

nginx的access.log日志输出请求总数、QPS和平均带宽

适用格式 #log_format main $remote_addr - $remote_user [$time_local] "$request" # $status $body_bytes_sent "$http_referer" # "$http_user_agent" "$http_x_forwarded_for"; 形如&#…

差分进化算法原理及其MATLAB/Python代码

1.算法简介 引用自&#xff1a;Storn R, Price K. Differential evolution–a simple and efficient heuristic for global optimization over continuous spaces[J]. Journal of global optimization, 1997, 11: 341-359. 今天给大家带来的是一个非常经典的智能优化算法–差分…

buu做题(6)

目录 [GWCTF 2019]我有一个数据库 [WUSTCTF2020]朴实无华 [GWCTF 2019]我有一个数据库 什么都没有, 尝试用dirsearch扫一下目录 可以扫到一个 /phpmyadmin 可以直接进入到数据库里面 但里面没什么东西 可以看到它的版本不是最新的, 搜一下相关的漏洞 phpMyAdmin 4.8.1后台文…

OCR识别采购单小程序管理助手

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…