《数据结构:单链表》

"希望就像星星,或许光芒微弱,但永不熄灭。"

博主的个人gitee:https://gitee.com/friend-a188881041351


一.概念与结构

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

单链表由一系列节点组成,每个节点包含两部分:

  1. 数据部分:存储实际的数据。

  2. 指针部分:存储指向下一个节点的指针。

单链表的特点是:

  • 每个节点通过指针连接到下一个节点。

  • 除了最后一个节点外,每个节点都有一个后继节点。

  • 单链表的头节点(头指针)是链表的入口。

二.单链表的定义

1.链表的组成

链表是由节点构成的。链表中每个结点都是独立申请的(即需要插入数据时才去申请⼀块结点的空间),我们需要通过指针变量来保存下⼀个结点位置才能从当前结点找到下⼀个结点。

2.链表的性质

  • 链式机构在逻辑上是连续的,在物理结构上不⼀定连续。
  • 结点⼀般是从堆上申请的。
  • 从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续。

3.单链表的定义

cpp 复制代码
typedef int SLTDataType;
typedef struct SListNode 
{
	SLTDataType data;
	struct SListNode* next;//指向下一个结点的指针
}SLTNode;

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

当我们想要从第⼀个结点走到最后⼀个结点时,只需要在当前结点拿上下一个结点的地址就可以了。

三.单链表的操作(增、删、查、改)

先在"List.h"中:

cpp 复制代码
//phead:头(首)结点
void SLTPrint(SLTNode* phead);

//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);

//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);

//尾删
void SLTPopBack(SLTNode** pphead);

//头删
void SLTPopFront(SLTNode** pphead);

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);

//在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);

//在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos);

//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos);


//销毁链表
void SListDestroy(SLTNode** pphead);

先写前置函数方便接下来的代码编写:

cpp 复制代码
//向操作系统申请一个新节点
SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

1.单链表插入元素

a.头插

cpp 复制代码
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

b.尾插

cpp 复制代码
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	//链表为空,phead直接指向newnode结点
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else 
    {   //链表不为空,找尾结点,将尾结点和新节点连接起来
		SLTNode* ptail = *pphead;
		while (ptail->next)//等价于ptail->next != NULL
		{
			ptail = ptail->next;
		}
		ptail->next = newnode;
	}
}

c.在指定位置之前插入数据

cpp 复制代码
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && pos);
	//pos就是头结点
	if (pos == *pphead)
	{
		//头插
		SLTPushFront(pphead, x);
	}
	else {
		SLTNode* newnode = SLTBuyNode(x);
		//pos在头结点之后--->找pos前驱节点
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//prev newnode  pos
		newnode->next = pos;
		prev->next = newnode;
	}
}

d.在指定位置之后插入数据

cpp 复制代码
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

2.单链表删除元素

a.尾删

cpp 复制代码
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead && *pphead);
	//只有一个结点的情况
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else 
    {
		SLTNode* prev = NULL;
		SLTNode* ptail = *pphead;
		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		//prev ptail
		prev->next = NULL;
		free(ptail);
		ptail = NULL;
	}
}

b.头删

cpp 复制代码
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);

	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

c.删除指定位置的数据

cpp 复制代码
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && pos);
	//要删除的结点刚好就是头结点---头删
	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else 
    {
		//prev
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//prev pos pos->next
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

d.删除指定位置之后的数据

cpp 复制代码
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos && pos->next);
	SLTNode* del = pos->next;
	pos->next = del->next;

	free(del);
	del = NULL;
}

3.单链表查找元素

cpp 复制代码
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	//未找到
	return NULL;
}

4.链表的销毁

cpp 复制代码
void SListDestroy(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

如有错误,恳请指正.

相关推荐
UP_Continue3 小时前
排序--归并排序
数据结构
飞鼠_3 小时前
详解数据结构之树、二叉树、二叉搜索树详解 C++实现
开发语言·数据结构·c++
丶Darling.4 小时前
26考研 | 王道 |数据结构 | 第二章 线性表
数据结构·考研
学也不会4 小时前
d2025331
java·数据结构·算法
Aurora_wmroy5 小时前
算法竞赛备赛——【数据结构】并查集
数据结构·c++·算法·蓝桥杯
pystraf6 小时前
P8310 〈 TREEのOI 2022 Spring 〉Essential Operations Solution
数据结构·c++·算法·线段树·洛谷
·醉挽清风·6 小时前
学习笔记—数据结构—二叉树(链式)
c语言·数据结构·c++·笔记·学习·算法
Susea&6 小时前
数据结构初阶:单链表
c语言·开发语言·数据结构
Wo3Shi4七7 小时前
二叉树数组表示
数据结构·后端·go
刃神太酷啦8 小时前
基础算法篇(3)(蓝桥杯常考点)-图论
数据结构·c++·算法·职场和发展·蓝桥杯·图论·蓝桥杯c++组