数据结构->链表篇

个人主页: ​​​​​​小则又沐风a

个人专栏:<C语言>

<数据结构>

目录

[一 链表的概念及概念:](#一 链表的概念及概念:)

[二 链表的分类](#二 链表的分类)

[1. 单向和双向](#1. 单向和双向)

[2. 带头或者不带头](#2. 带头或者不带头)

3.循环和非循环

[三 链表的实现](#三 链表的实现)

[1. 链表的结构](#1. 链表的结构)

[2. 动态申请一个结点](#2. 动态申请一个结点)

3.单链表打印

4.单链表尾插

5.单链表的头插

[6. 单链表的尾删](#6. 单链表的尾删)

[7. 链表的头删](#7. 链表的头删)

[8. 单链表查找](#8. 单链表查找)

9.单链表在pos位置之后插入x

10.单链表删除pos位置之后的值


一 链表的概念及概念:

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

这样的解释有点抽象我们来看一张图:

我们把每个数据看作每一个车厢,如果没有连接车厢的装置的话,那么每个车厢就是独立的.

链表也是如此.

我们通过上面的图可以知道我们的每组数据在逻辑上一定是连续的,但是在物理上不一定是连续的,

我们通过记录下一个节点的地址实现每个节点的链接.

二 链表的分类

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

1. 单向和双向
2. 带头或者不带头
3.循环和非循环

纵使有这么多的类型但是使用率最高的是

1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现了就知道了。

三 链表的实现

下面我实现的是无头单向非循环的链表

在实现链表的各个接口之前我们先来定义一下链表的结构:

1. 链表的结构
cpp 复制代码
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

data表示的这个节点存储的数据.

next存储的是下一个节点的地址.

2. 动态申请一个结点

通过malloc开辟一个节点的空间,并且检查是否开辟成功,然后给节点赋值.

cpp 复制代码
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* temp = (SListNode*)malloc(sizeof(SListNode));
	if (temp == NULL)
	{
		perror("malloc");
		return;
	}
	temp->data = x;
	temp->next = NULL;
	return temp;
}
3.单链表打印
cpp 复制代码
void SListPrint(SListNode* plist)
{
	SListNode* cur = plist;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

在这里我们通过这样的方式来遍历链表直到遍历到NULL;

这样就实现了链表的打印.

4.单链表尾插

所以我们先要找尾节点.

cpp 复制代码
void SListPushBack(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* newnode=BuySListNode(x);
	if (*pplist == NULL)
	{
		*pplist = newnode;
	}
	else
	{
		SListNode* cur = *pplist;
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		cur->next = newnode;
		newnode->next = NULL;
	}
}

注意在这里我们要传入的是二级指针因为有可能我们传入的链表是一个空链表,此时我们需要让链表的第一个节点不再指向NULL让他指向newnode所以我们需要的是地址传递.

**5.**单链表的头插

头插只需要让newnode的next指向原来的头节点,然后将头节点更新为newnode即可

cpp 复制代码
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* newnode = BuySListNode(x);
	newnode->next = *pplist;
	*pplist = newnode;
}
6. 单链表的尾删

我们需要找到指向尾节点的节点让他的next指向NULL然后释放尾节点.

cpp 复制代码
void SListPopBack(SListNode** pplist)
{
	assert(pplist&&*pplist);
	if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* cur = *pplist;
		while (cur->next->next != NULL)
		{
			cur = cur->next;
		}
		SListNode* del = cur->next;
		cur->next = NULL;
		free(del);
		del = NULL;
	}
	
}

如果链表只有一个节点的话直接释放掉头节点,然后置空.

7. 链表的头删

如果我们先把头节点释放掉的话,我们就无法找到下一个节点,所以我们需要先记录下下一个节点,再释放空间.

cpp 复制代码
void SListPopFront(SListNode** pplist)
{
	assert(pplist && *pplist);
	if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* cur = (*pplist)->next;
		free(*pplist);
		*pplist = cur;
	}
}
8. 单链表查找

遍历链表,如果找到直接返回节点,如果找不到就返回空指针.

cpp 复制代码
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* cur = plist;
	while (cur != NULL)
	{
		if (cur->data == x)
		{
			return cur;
		}
		else
		{
			cur = cur->next;
		}
	}
	return NULL;
}
9.单链表在pos位置之后插入x

如果我们直接将pos->next修改为我们创建的新节点的话,那么我们之前的pos之后的节点就找不到了,所以我们要先记录下来这个pos之后的节点.

cpp 复制代码
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	SListNode* next = pos->next;
	pos->next = newnode;
	newnode->next = next;
}
10.单链表删除pos位置之后的值

同理的如果直接删除节点的话我们就无法访问删除节点的下一个节点了,所以我们要先记录下来这个节点,再删除.

cpp 复制代码
void SListEraseAfter(SListNode* pos)
{
	assert(pos && pos->next);
	SListNode* next = pos->next->next;
	free(pos->next);
	pos->next = next;
}

至此,链表的接口实现全部的代码和讲解都展示在了上面,,我们通过画图就可以更快的理解这些接口,

希望这篇文章能够帮助到大家理解链表的知识.

谢谢大家的观看!!!

相关推荐
HSunR1 小时前
ruoyi 若依 自定义注解 参数校验
java·前端·数据库
拆房老料2 小时前
ONLYOFFICE也能像Microsoft Word和WPS一样分别设置中西文字体
前端·html·word·开源软件·wps
Solis程序员3 小时前
Stripe 幂等表:把「不确定的重试」变成「查表返回」
前端·安全·bootstrap·php·agent
李纲明3 小时前
WordPress 站点变慢:按 TTFB → 缓存 → 查询 → 前端 分层排查(含配置注意)
前端·缓存·性能优化·wordpress·后端开发
程序人生8883 小时前
PDF 转 Word 版式错乱、表格丢失?DocConverter Web 格式互转引擎的保真实践
前端·人工智能·opencv·机器学习·pdf·word
粥里有勺糖4 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
xy34534 小时前
Axure 9.0 动态面板基本操作
前端·ui·html·axure·原型·产品设计
不停喝水4 小时前
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
java·前端·数据库
一水鉴天5 小时前
统一对象拓扑(UOT)设计全链定稿:从三件事分离到三继承 之1 20261010(豆包“查看聊天内容”继续)
前端·css
栖凤5 小时前
Java 的 try-catch 在 Agent 里失效了,我用了 5 个模式才兜住
java·前端·python