数据结构——单链表

不能毁灭我的,终将使我更强大  

文章目录

一、链表

二、单链表

三、实现单链表

1.定义节点

2.由数据生成节点

3.连接并打印链表

4.单链表的基本接口

头插

头删

尾插

尾删

由数据Data找节点

在pos之前插入节点

在pos之后插入节点

删除pos节点

删除pos之后的节点 


  大家好,我是纪宁。

  上篇文章介绍了数据结构的入门——顺序表,比较简单。这篇文章我们来学习链表(单链表),难度稍微增加了一点,不过只要C语言的结构和指针部分的知识扎实,那么也是可以轻松拿捏的。

  注:博主也在持续学习中,如知识点或代码有问题欢迎在评论区指出。

指针icon-default.png?t=N6B9http://t.csdn.cn/4kCnXC语言自定义类型icon-default.png?t=N6B9http://t.csdn.cn/VEicT

一、链表

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

  这里非连续的意思就是链表的每一部分可以在内存的任意一块区域存在,且这块区域的地址是随机的,所以一般用动态内存来开辟这块空间的地址。链表的每一部分都称为一个节点,每个节点分为两部分:数据域和指针域

  链表分为单链表、双向链表和循环链表

二、单链表

  单链表的结构比较简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多,后面博主会专门出一个关于单链表刷题的文章,大家继续关注。

  单链表的每个节点分为两部分,一部分存储数据,一部分存储下一个节点的地址。前一个节点中存储着下一个节点的地址,这也是单链表能连起来的原因。

三、实现单链表

  这部分先介绍单链表的基本结构,再介绍单链表的增删查改等基本接口。

1.定义节点

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType Data;
	struct SListNode* next;
}SLTNode;

  将单链表中的数据类型重定义为 SLDataType 类型,并定义一个单链表节点的结构体,其中节点的一部分是当前节点的数据,另一部分则是指向下一节点的指针。

2.由数据生成节点

SLTNode* BuySListNode(SLTDataType x)
{
	SLTNode* nownode=(SLTNode*)malloc(sizeof(SLTNode));
	if (nownode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	else 
	{
		nownode->Data = x;
		nownode->next = NULL;
		return nownode;
	}
}

  首先,每次生成节点都要开辟一个节点的空间,开辟成功后,将它的数据域赋值为 x ,指针域赋值为NULL,并返回开辟的空间强转后的首地址。

3.连接并打印链表

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->Data);
		cur = cur->next;
	}
	printf("NULL\n");
}

  将链表的头指针赋值给一个节点类型的指针,然后使用这个节点指针对单链表进行遍历。

4.单链表的基本接口

头插

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode*nownode = BuySListNode(x);
	nownode->next = *pphead;
	*pphead = nownode;
}

  单链表的头插只需要让链表的头指针的指向要插入的节点,再让这个节点的指针域指向原来头节点的地址。需要注意的是要改变头指针的指向,需要将头指针的地址作为函数参数传过去,并用一个二级指针接收,解引用时即可改变头指针的指向。

  方法是先用一个指针将生成的节点地址存起来,然后将它的指针域改为原来的头节点,最后让头指针指向新生成的节点。

头删

void SLTPopFront(SLTNode** pphead)
{
	assert(*pphead);
	if ((*pphead)->next==NULL)
	{
		*pphead = NULL;
	}
	else
	{
		SLTNode* oldnode = *pphead;
		*pphead = (*pphead)->next;
		free(oldnode);
        oldnode=NULL;
	}
}

  单链表的头删要分为一个节点和多个节点的情况。

  当发现头指针指向的头节点的指针域为空时,说明这个单链表只有一个节点,那么只需要将这个节点指针置空即可。

  否则,说明这个单链表至少有两个节点,则要用另一种方法:因为第一个节点中存储着第二个节点的地址,所以要先将第一个节点的指针域存起来,然后,将这个地址赋值给头指针,最后将头节点开辟的空间释放

尾插

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* nownode = BuySListNode(x);
	if (*pphead == NULL)
	{
		*pphead = nownode;
	}
	else
	{
		SLTNode* nod = *pphead;
		while (nod->next != NULL)
		{
			nod = nod->next;
		}
		nod->next = nownode;
	}
}

  单链表的尾插要看单链表中是否已有节点。

  如果单链表中没有节点,就将头指针指向新创建的节点。如果单链表中已有节点,就得先找到最后一个节点的位置,再改变最后一个节点的指针域指向新创建的节点。

尾删

void SLTPopBack(SLTNode** pphead)
{
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		/*SLTNode* nod = *pphead;*/
		/*while (nod->next->next != NULL)
		{
			nod = nod->next;
		}
		free(nod->next);
		nod->next = NULL;*/
		SLTNode* tail= *pphead;
		SLTNode* tailprev = NULL;
		while (tail->next != NULL)
		{
			tailprev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		tailprev->next = NULL;
	}
}

  单链表的尾删也分为两种:一个节点和多个节点。

  单链表只有一个节点的时候,直接将它的这个节点空间释放。当有多个节点的时候,首先要找到最后与一个节点的位置,将最后一个节点释放掉,并要让让倒数第二个节点的指针域置空。因为当只有一个节点的时候要改变头节点的指向,所以函数传参也要传头指针的地址

由数据Data找节点

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		if (cur->Data == x)
			return cur;
		else
		{
			cur = cur->next;
		}
	}
		return NULL;
}

在pos之前插入节点

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	if (pos== *pphead)//头插
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* cur = *pphead;
		while (cur->next != pos)
		{
			cur = cur->next;
		}
		SLTNode* prewnode = NULL;
		prewnode = BuySListNode(x);
		prewnode->next = pos;
		cur->next = prewnode;
	}
}

在pos之后插入节点

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

删除pos节点

void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	if (pos == *pphead)
	{
		*pphead = (*pphead)->next;
	}
	else
	{
		SLTNode* cur = *pphead;
		while (cur->next != pos)
		{
			cur = cur->next;
		}
		cur->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

  删除pos节点,首先得找到pos节点前面的节点(所以要传头指针进行遍历),让它的指针域指向pos的下一个节点,再将pos节点释放。 传头指针地址的原因是有可能要删除的就是第一个节点,要改变头指针指向。

删除pos之后的节点 

void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);//检查尾节点
	SLTNode*node = pos->next;
	pos->next = node->next;
	free(node);
	node = NULL;
}

单链表的实现及基本接口就介绍到这里,下篇文章将更新单链表常见的一些面试、笔试题。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Matplotlib_绘制柱状图

绘制柱状图 🧩bar方法 bar()是Matplotlib.pyplot库中用于绘制条形图(bar chart)的函数。条形图是一种常见的数据可视化图表,用于显示不同类别之间的比较。 函数签名: matplotlib.pyplot.bar(x, height, width0.8, …

【KO】vite使用 git bash here创建vue3项目时方向键失败!

文章目录 起因过程结果 起因 今天使用vite创建ue3项目,因为git使用习惯了就直接用git运行创建命令,前两步都没啥问题,到选择框架的时候问题来了,方向键无效。如图: 过程 常理来说是直接用方向键↑和↓进行选择&…

3d激光slam建图与定位(1)_基于ndt算法定位

一.代码实现流程 二.ndt算法原理 一.该算法定位有三个进程文件 1.map_loader.cpp用于点云地图的读取,从文件中读取点云后对这个点云地图进行旋转平移后发布点云地图到ros #include "map_loader.h"MapLoader::MapLoader(ros::NodeHandle &nh){std::st…

【深度学习笔记】动量梯度下降法

本专栏是网易云课堂人工智能课程《神经网络与深度学习》的学习笔记,视频由网易云课堂与 deeplearning.ai 联合出品,主讲人是吴恩达 Andrew Ng 教授。感兴趣的网友可以观看网易云课堂的视频进行深入学习,视频的链接如下: 神经网络和…

Python开发之手动实现一维线性插值

Python开发之手动实现一维线性插值 1.线性插值法介绍2.手动实现线性插值3.案例一:手动实现线性插值4.使用pandas的插值方法实现要求(推荐)5.案例二:对一组数据进行线性插值和SG滤波处理 前言:主要介绍手动实现一维线性插值以及pandas里面的in…

【Docker】容器的数据卷

目录 一、数据卷的概念与作用 二、数据卷的配置 三、数据卷容器的配置 一、数据卷的概念与作用 在了解什么是数据卷之前我们先来思考以下这些问题: 1.如果我们一个容器在使用后被删除,那么他里面的数据是否也会丢失呢?比如容器内的MySQL的…

2023年的深度学习入门指南(21) - 百川大模型

2023年的深度学习入门指南(21) - 百川大模型 前面我们用了三节的篇幅介绍了目前最强大的开源模型LLaMA2。这一节我们说一说国产大模型的一个代表,百川大模型。 使用百川大模型 第一步我们先把百川用起来,然后再研究如何训练和其原理如何。 百川的使用…

Mybatis使用collection映射一对多查询分页问题

场景&#xff1a;页面展示列表&#xff0c;需要查询多的字段&#xff0c;和一的字段。并且还要分页。 这时候直接想到的是手写sql。 /*** 标签*/private List<BasicResidentTags> tags;Data TableName("basic_resident_tags") public class BasicResidentTag…

vue3 - element-plus 上传各种 word pdf 文件、图片视频并上传到服务器功能效果,示例代码开箱即用。

效果图 在 vue3 项目中,使用 element plus 组件库的 el-upload 上传组件,进行文件、图片图像的上传功能示例。 完整代码 可直接复制,再改个接口地址。 在这里上传图片和文件是分成

新产品:Stimulsoft Forms 2023.3.1 Crack

Stimulsoft Forms 是一个用于交互式收集和处理用户数据的组件。表单工具可以轻松集成到您的项目或应用程序中&#xff0c;具有直观且用户友好的界面&#xff0c;并允许您创建丰富的表单模板。Stimulsoft Forms 是应用程序中与用户交互的新水平 什么是 Stimulsoft Forms&#xf…

华为数通HCIP-EVPN基础

MP-BGP MP-BGP&#xff08;Multiprotocol Extensions for BGP-4&#xff09;在RFC4760中被定义&#xff0c;用于实现BGP-4的扩展以允许BGP携带多种网络层协议&#xff08;例如IPv6、L3VPN、EVPN等&#xff09;。这种扩展有很好的后向兼容性&#xff0c;即一个支持MP-BGP的路由…

cad丢失mfc140u.dll怎么办?找不到mfc140u.dll的解决方法

第一&#xff1a;mfc140u.dll有什么用途&#xff1f; mfc140u.dll是Windows操作系统中的一个动态链接库文件&#xff0c;它是Microsoft Foundation Class (MFC)库的一部分。MFC是 C中的一个框架&#xff0c;用于构建Windows应用程序的用户界面和功能。mfc140u.dll包含了MFC库中…

Flowable-中间事件-信号中间抛出事件

定义 当流程执行到达信号抛出事件时&#xff0c;流程引擎会直接抛出信号&#xff0c;其他引用了与其相同的信号捕获 事件会被触发&#xff0c;信号发出后事件结束&#xff0c;流程沿后继路线继续执行。其抛出的信号可以被信号开始事 件&#xff08;Signal Start Event&#xf…

从官网认识 JDK,JRE,JVM 三者的关系

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ JVM 是一些大厂面试必问点&#xff0c;要想解决 OOM、性能调优方面的问题&#xff0c;掌握 JVM 知识必不可少&#xff0c;从今天开始&#xff0c;将为大家介绍 JVM 的常用知…

css实现有缺口的border

css实现有缺口的border 1.问题回溯2.css实现有缺口的border 1.问题回溯 通常会有那种两个div都有border重叠在一起就会有种加粗的效果。 div1,div2,div3都有个1px的border&#xff0c;箭头标记的地方是没有处理解决的&#xff0c;很明显看着是有加粗效果的。其实这种感觉把di…

【Vscode】远程内存占用大

查看远程服务器上的扩展 依次删除&#xff0c;重新连接后观察内存占用 此扩展占用较高&#xff0c;约2G&#xff08;前后端项目&#xff0c;依赖较多导致&#xff09;

【node.js】04-模块化

目录 一、什么是模块化 二、node.js中的模块化 1. node.js中模块的分类 2. 加载模块 3. node.js 中的模块作用域 4. 向外共享模块作用域中的成员 4.1 module对象 4.2 module.exports 对象 4.3 exports对象 5. node.js 中的模块化规范 一、什么是模块化 模块化是指解…

为Android构建现代应用——主体结构

创建Screents和ViewModels 在前面的章节中&#xff0c;我们已经分析了OrderNow项目的理论概念和我们将赋予的组织。 在本章中&#xff0c;我们将开始实现初始结构和模板&#xff0c;这将联接每一个应用程序的部分。 首先将添加以下带有各自视图模型的主屏幕&#xff1a; •…

springboot 之以enable开头的注解

Spring​ 有很多 Enable 开头的注解&#xff0c;平时在使用的时候也没有注意过为什么会有这些注解 Enable 注解 首先我们先看一下有哪些常用的 Enable 开头的注解&#xff0c;以及都是干什么用的。 EnableRetry​&#xff1a;开启Spring 的重试功能&#xff1b; EnableSch…

【环境配置】Windows下WSL将ubuntu挪位置-系统盘清理

问题–垃圾太多&#xff0c;系统盘空间占用太大 最近 C 盘空间暴涨&#xff0c;用工具 WinDirStat-强烈推荐的工具 查看发现 WSL 子系统占用了6个多 G 的空间&#xff0c;遂想办法挪个位置&#xff1b; 【关键字】将 Windows 里的子系统挪到非系统盘 D 盘&#xff1b; 解决 打…