线性表的链式存储结构——链表

news2024/11/26 10:16:00

一、顺序表优缺点

优点:我们知道顺序表结构简单,便于随机访问表中任一元素;

缺点:顺序存储结构不利于插入和删除,不利于扩充,也容易造成空间浪费。

二、链表的定义

①:概念:

用一组任一的存储单元存储线性表的数据元素(可以是连续,也可以是不可连续的),数据元素之间的逻辑关系借助指示元素存储位置的指针来表示,这种存储方式叫做线性表的 链式存储结构 ,简称 链表

②:结点

为了表示数据元素间的逻辑关系,除了存储数据本身信息之外,还需要存放其直接后继的存储位置(地址),这两部分(数据域和指针域)组成一个 结点 用于表示一个元素。
数据域:存储数据元素的信息;
指针域:存放直接后继的元素的地址。
表示图如下:
同时还需要注意以下几点:
注意:我们规定链表的尾结点(最后一个结点)的指针域为NULL,这样可以方便进行操作。

③:单链表的定义:

若链表的每个结点只包含一个指针域,则称此链表为 线性链表单链表

④:头结点:

有时为了操作方便,在单链表的第一个结点之前添加一个结点,称为 头结点或伪结点
不带哨兵的头结点就直接使用;
带哨兵的头结点就按以下规则:
头结点的数据域可以不存放任何信息,也可以存放其他特殊信息;
头结点的指针域存放第一个结点的存储地址,即指向第一个结点;
本次小编用的是不带哨兵的头结点。
有头结点的单链表叫做“带头结点的单链表”。

三 、单链表的C语言结构定义:

typedef int SLDataType;//方便以后跟改数据类型

typedef struct SLisrNode
{
	SLDataType data;//数据域
	struct SListNode* next;//指针域
}Lnode, * LinkList;//用typedef重定义后,Londe为结点类型,LinkList为指向结点的指针类型


四、单链表基本操作:

作几点说明

①:为了方便让大家感受一下单链表,所以先实现遍历单链表,让大家体会其结构的韵味;

②:我们一般都默认用带有头结点的单链表;

③:大家一般都会写与控制台有互动的代码,但小编这里只是带大家入门上手,只是简单实现,所以大家可以根据小编的思路自行设计。

④:本次实现小编也是采用多文件操作,没听说过的小伙伴可以大致了解一下,就几句话意思很简单。

⑤:跟往常不一样的是,小编会把详细说明放在注释里面,大家请认真解读,有疑问或没看懂的欢迎大家评论区讨论。

四.1、遍历单链表

源代码:

//遍历单链表
void SLTPrint(SLTNode* phead)
{
	//一般头指针phead我们都不会动,方便我们多次操作
	//所以我们可以创建一个临时指针来进行操作
	SLTNode* tmp = phead;
	//因为单链表尾结点的指针域为NULL,所以循环条件可以为tmp
	//当tmp为NULL时,说明链表遍历完成,并且退出循环
	while (tmp)
	{
		//打印数据域(打印"->"只是方便展示链表结构)
		printf("%d->", tmp->data);
		//因为指针域指向下一个结点,所以可以通过赋值方法找到下一个结点
		tmp = tmp->next;
	}
	//方便展示链表结构,所以末尾打印一个NULL
	printf("->NULL\n");
}

四.2、用malloc函数创建新结点

因为指针phead刚开始创建时并没有指向任何结点,需要在程序执行过程中通过按结点的类型向系统申请建立一个新结点,通过调用标准函数malloc动态开辟空间生成,

创建一个新结点,具体格式如下:

phead=(SLTNnode*)malloc(sizeof(SLTNode));

当phead结点不需要时,我们应该用free函数释放空间,收回结点;

因为有多种操作,所以我们将这个操作写成一个函数,方便后续调用;

源代码:

//创建新结点
//因为要返回动态申请的结点,所以有返回类型
SLTNode* BuySLiseNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	//判断是否开辟成功
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	//填充数据
	newnode->data = x;
	newnode->next = NULL;
	//返回
	return newnode;
}

四.3、尾插法

尾插法:顾名思义就是在链表尾部进行插入数据;

大致步骤分为两步:

①:找到链表尾结点(根据尾结点的next域为NULL来作为循环条件进行寻找);

②:将新结点链接到尾结点的next域即可;

源代码即解释如下:

//尾插法
//函数第一个形参是二级指针,是存储链表的地址,用的传址调用
//函数第二个形参是要插入的数据
void SLTPushBack(SLTNode** pphead1, SLTDataType x)
{
	//得到一个新结点
	SLTNode* newnode = BuySLiseNode(x);
	//若链表为空链表,则直接将新结点赋值给链表,因为我们是传址调用,可以改变外面链表的内容
	if (*pphead1 == NULL)
	{
		*pphead1 = newnode;
	}
	else
	{
		//同理将链表拷贝到一个临时结点中便于操作
		SLTNode* tmp = *pphead1;
		//①:找到尾结点
		//因为尾结点的next域为NULL,所以可以作为循环判断条件
		while (tmp->next == NULL)
		{
			tmp = tmp->next;
		}
		//②:链接
		tmp->next = newnode;
		//这里可能有的小伙伴不理解,"觉得这里不也是直接赋值吗,怎么改变外部链表的"?
		//所以大家就要注意一句话,如下:
		//1.改变结构体,用结构体指针
		//2.改变结构体指针,要用结构体指针的指针(二级指针)
		// 
		//上面的pphead就是一个结构体二级指针,用于改变结构体指针
		//但这里的next是结构体成员,所以我们只需要改变结构体,所以就用结构体指针
		//而tmp本来就是我们结构头指针拷贝过来的,所以改变了tmp的next就相当于改变了外部链表的尾结点的next
	}

	//因为tmp、newnode这些都是局部变量,函数结束后会自动销毁
	//第二次又会从初始位置开始操作,所以我们不用调整这些变量的值
	//但链表结点内容不会被销毁,因为我们是用malloc函数在堆区上面申请的空间,只有free后才会销毁
}

测试结果:

void TestList2()
{
	SLTNode* phead = NULL;//头结点,用于链接新结点
	//尾插100、200、300
	SLTPushBack(&phead, 100);
	SLTPushBack(&phead, 200);
	SLTPushBack(&phead, 300);
	//打印
	SLTPrint(phead);

}

int main()
{
	//测试
//	TestSLTist1();
	TestList2();
	return 0;
}

运行结果:

四.4、头插法

当我们理解清楚尾插法里面的各种细节后,头插以及后面的操作都会觉得很简单;

头插大致分为

①:将新结点的next域指向首结点;

②:再让头指针指向新结点;

源代码及解释如下:


//头插法
//形参和尾插法是相同的道理
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	//因为我们每一步都要使用不带哨兵的头结点,所以每次都要改变结构体指针
	// 所以形参用二级指针是必须的,并且不用区分链表是否为空
	//先得到一个新结点
	SLTNode* tmp = BuySLiseNode(x);
	//①:新结点的next域指向首结点
	tmp->next = *pphead;
	//②:头结点指向新结点
	*pphead = tmp;
}

四.5、尾删法

尾删法也涉及到许多细节,大家也需要仔细思考;

因为我们使用的是不带哨兵的头指针,就会涉及改变结构体和改变结构体指针的问题;

只要记住:

改变next和data域就是改变结构体,只需要使用结构体指针;

改变头指针就是改变结构体指针,这时需要结构体二级指针;

尾删法分为三中=种情况:

①:链表为空;

②:链表里面只有一个结点;

③:链表里面有两个或两个以上的结点;

具体细节看注释:
源代码如下:


//头删法
//形参是结构体二级指针,因为分为几种情况,有一种情况会改变结构体指针
void SLTPopBack(SLTNode** pphead)
{
	//情况一:链表为空则提示删除失败
	if (*pphead == NULL)
	{
		printf("此链表为空,无法删除!\n");
		return;
	}
	//情况二:只有一个结点,此时需要使用头指针,所以要用到二级指针
	//直接用free释放掉头指针即可,因为我们用的是不带哨兵的头指针,头指针指向的就是首元素
	//又因为只有一个元素,所以直接释放头指针,在将头指针置空即可
	//
	if((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		//情况三:有两个及其以上的结点:步骤如下:
		//①:定位到尾结点;
		//②:释放尾结点;
		//将尾结点的前一个结点的next域置空(所以一定要保存前一结点的地址)

	//同理先将链表内容拷贝到临时指针中进行操作,因为我们操作的是结构体,所以用结构体指针即可实现
		SLTNode* tmp = *pphead;
		//如果tmp->next->next为NULL,说明tmp->next就是尾结点,tmp就是尾结点的前一个结点,所以就可以进行释放了
		while (tmp->next->next)
		{
			tmp = tmp->next;
		}
		free(tmp->next);
		tmp->next = NULL;
	}
}

四.6、头删法

头删法比较简单,但因为是在头部操作,所以每一步都是在改变结构体指针(即头指针),所以每一步都要用结构体二级指针,所以形参是结构体二级指针;

头删法只有两种情况:

①:链表为空,与尾删一样;

②:链表不为空;这里没有区分一个结点和多个结点是因为我们每一步都要用到结构体二级指针,所以两者操作是一样的;

具体细节即源代码如下:

//头删法
//参数同尾删一样,会改变结构体指针,所以用结构体二级指针
void SLTPopFront(SLTNode** pphead)
{
	//情况一:链表为空,同尾删一样
	if (*pphead == NULL)
	{
		printf("此链表为空,无法删除!\n");
		return;
	}

	//情况二:链表不为空
	//①:先将第二个结点的地址(即(*pphead->next))保存到临时指针
	//②:再释放头指针(即释放首元素)
	//③:再将存放第二个结点地址的临时指针赋给头指针*pphead
	SLTNode* nextnode = (*pphead)->next;
	free(*pphead);
	*pphead = nextnode;
}

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

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

相关文章

springmvc-页面跳转表单标签其他标签tomcat控制台中文乱码问题

1. WEB-INF下页面跳转 容器启动后,如何默认显示web-inf目录下的系统首页。 2. ModelAttribute来注解非请求处理方法 用途:预加载数据,会在每个RequestMapping方法执行之前调用。 特点:无需返回视图,返回类型void 示例…

【计算机网络黑皮书】应用层

【事先声明】 这是对于中科大的计算机网络的网课的学习笔记,感谢郑烇老师的无偿分享 书籍是《计算机网络(自顶向下方法 第6版)》 需要的可以私信我,无偿分享,课程简介下也有 课程连接 目录 应用层网络应用的原理应用架…

[BJDCTF2020]The mystery of ip

打开环境 点击flag,提示ip,这里确实就比较容易联想到x-forwarded-for 点击hint 这个好像没啥用 使用bp抓包 添加请求头 X-Forwarded-For:1 试一下 发现ip可控 后来查了发现 PHP可能存在Twig模版注入漏洞 参考https://www.cnblogs.com/zzjdbk/p/13…

Scala第十七章节

Scala第十七章节 scala总目录 文档资料下载 章节目标 了解集合的相关概念掌握Traversable集合的用法掌握随机学生序列案例 1. 集合 1.1 概述 但凡了解过编程的人都知道程序 算法 数据结构这句话, 它是由著名的瑞士计算机科学家尼古拉斯沃斯提出来的, 而他也是1984年图灵…

ADO连接Access的前期绑定方法实例(下)

【分享成果,随喜正能量】眾生多悲苦,發願‬菩提心。願今天所有聽見我、看見我、憶念我的眾生,因我心而‬生喜悅!除消身心的痛苦!種下脫解‬的種子!願我等‬身心念力所及之處一切眾切‬生因佛得度&#xff0…

【AI视野·今日CV 计算机视觉论文速览 第258期】Mon, 2 Oct 2023

AI视野今日CS.CV 计算机视觉论文速览 Mon, 2 Oct 2023 (showing first 100 of 112 entries) Totally 100 papers 👉上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Multi-task View Synthesis with Neural Radiance Fields Authors Shuhong Zheng, Zh…

Vue的模板语法

Vue的模板语法 Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。 测试准备 为了方便测试,先将vue-base项…

【AI视野·今日Robot 机器人论文速览 第四十五期】Mon, 2 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Mon, 2 Oct 2023 Totally 42 papers 👉上期速览✈更多精彩请移步主页 Daily Robotics Papers Learning Decentralized Flocking Controllers with Spatio-Temporal Graph Neural Network Authors Siji Chen, Yanshen Sun, …

守护进程解析

什么是守护进程? - 知乎 什么是守护进程:生存期长的一种进程,没有控制终端。它们常常在系统引导装入时启动,仅在系统关闭时才终止。 进程组 : 每个进程除了有一个进程ID之外,还属于一个进程组进程组是一…

【已解决】opencv 交叉编译 ffmpeg选项始终为NO

一、opencv 交叉编译没有 ffmpeg ,会导致视频打不开 在交叉编译时候,发现在 pc 端能用 opencv 打开的视频,但是在 rv1126 上打不开。在网上查了很久,原因可能是 交叉编译过程 ffmpeg 造成的。之前 ffmpeg 是直接用 apt 安装的&am…

LeetCode 周赛上分之旅 #49 再探内向基环树

⭐️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度…

1300*C. Coin Rows(枚举模拟)

解析: 两人都绝对聪明,Alice先走,尽量让Bob所能拿的分数最少,Alice有一次往下走的机会,剩余没走过的点正好分为两断断开的区域,所以Bob的最大分数要么在第一格向下或者在最后一列向下。 遍历区间&#xff0…

笔训day2

选择题 1、输出格式 此题与昨天的题类似,有“-”号时是左对齐,%-m.n m表示宽度,n表示左起取n位数。 2、常量指针和指针常量 //两种都是常量指针 const int *p1; int const *p2; //指针常量 int* const p3 3、字符数组和字符指针 4、函数…

国庆节看这里,有你意想不到的收货!(建议收藏)

计算机视觉研究院专栏 作者:Edison_G “国庆长假,每个人都安耐不住了,但是,在你静心、游玩的时候,还是可以阅读今天的分享,干货满满! 公众号ID|ComputerVisionGzq 学习群&#xff5c…

基于SSM的医院住院综合服务管理系统的设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用Vue技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

数据结构与算法(C语言版)P9---哈夫曼树

1、哈夫曼树的基本概念 (1)路径:从树中一个结点到另一个结点之间的__分支__构成这两个结点间的路径。 (2)__结点的路径长度:__两结点间路径上的分支树。 练习:计算下面二叉树结点之间的路径长…

1.7.C++项目:仿muduo库实现并发服务器之Poller模块的设计

项目完整在: 文章目录 一、Poller模块:描述符IO事件监控模块二、提供的功能三、实现思想(一)功能(二)意义(三)功能设计 四、封装思想五、代码(一)框架&#…

基于微信小程序的懒人美食帮外卖订餐设计与实现(亮点:多角色的订餐系统、最贴近现实的小程序)

文章目录 前言系统主要功能:具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

CH347读取MPU6050传感器数据和显示

MPU6050 是一款集成了六轴加速度计和陀螺仪的微电子机械系统(MEMS)传感器。它由 InvenSense(现为 TDK) 公司开发,是一种广泛应用于姿态估计、运动追踪和稳定控制等领域的常用传感器。 MPU6050 具有以下主要特点和技术…

1、【开始】【简介】Qlib:量化平台

【简介】1、Qlib:量化平台 简介框架简介 Qlib是一个面向AI的量化投资平台,旨在实现AI技术在量化投资中的潜力,赋能研究,并创造价值。 通过Qlib,用户可以轻松利用他们的想法来创建更好的量化投资策略。 框架 在模块层,Qlib 是由上述组件组成的平台。这些组件被设计为低耦…