数据结构——单链表

概念与结构

概念:

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

链表结构:

结点

与顺序表不同的是,链表里的每节"车厢"都是独立申请下来的空间,我们称之为"结点"。

  • 结点的组成主要有两个部分:当前结点要保存的数据和保存下一个结点的地址。
  • 图中指针变量plist保存的是第一个结点的地址,我们称*plist此时指向第一个结点,*如果我们希望plist指向第二个节点时,只需要修改plist保存的地址为0x00000B.
  • 链表中每个结点都是独立申请的(即需要插入数据时才去申请一块结点的空间),我们需要通过指针变量来保存下一个结点位置才能从当前结点找到下一个结点。

链表的性质

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

假设我们当前保存的结点为整型:

cpp 复制代码
struct SListNode
{
	int data;//结点数据
	struct SListNode* next;//指针变量:用来保存下一个结点的地址
};

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

链表的打印

cpp 复制代码
typedef int SLDateType;
typedef struct SListNode
{
	SLDateType data;
	struct SListNode* next;
}SLTNode;
void SLPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		printf("%d", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}

当我们想要保存的数据类型为浮点型,字符型时,我们也可以改变。

链表的实现

接下来我们来实现这些函数

cpp 复制代码
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
//需要找到pos之前的位置
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);

// 在pos的前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x);
// 删除pos位置
//需要找到pos之前的位置
void SLTErase(SListNode** pphead, SListNode* pos);
void SLTDestroy(SListNode** pphead);
cpp 复制代码
//向操作系统申请一个新空间
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
cpp 复制代码
void SListPrint(SListNode* plist)
{
	SListNode* pcur = plist;
	while (pcur)
	{
		printf("%d ", pcur->data);
		pcur = pcur->next;

	}
	printf("\n");
}
cpp 复制代码
void SListPushBack(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* newnode = BuySListNode(x);
	//链表为空
	if (*pplist == NULL)
	{
		*pplist=newnode;
	}
	//链表不为空
	else
	{
		SListNode* ptail = *pplist;
		while (ptail->next!=NULL)
		{
			ptail = ptail->next;
		}
		ptail->next = newnode;
	}
	
}
cpp 复制代码
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	assert(pplist);
	SListNode* newnode = BuySListNode(x);
	newnode->next = *pplist;
	*pplist = newnode;
}
cpp 复制代码
void SListPopBack(SListNode** pplist)
{
	assert(pplist && *pplist);
	//只有一个结点
	if ((*pplist)->next == NULL)
	{
		free(*pplist);
		*pplist = NULL;
	}
	else
	{
		SListNode* prev=NULL, * ptail=*pplist;
		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		free(ptail);
		ptail = NULL;
		prev->next = NULL;
	}
	
}
cpp 复制代码
void SListPopFront(SListNode** pplist)
{
	assert(pplist && *pplist);
	SListNode* pcur = *pplist;
	*pplist = pcur->next;
	free(pcur);
}
cpp 复制代码
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	SListNode* pos = plist;
	while(pos)
	{
		if (pos->data == x)
		{
			return pos;	
		}
		pos = pos->data;
	}
	return NULL;
	
}
cpp 复制代码
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
cpp 复制代码
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{
	
	assert(pphead && *pphead && pos);
	SListNode* prev = *pphead;
//pos为第一个结点时
	if (pos == *pphead)
		SListPushFront(pphead, x);
	else
	{
		SListNode* newnode = BuySListNode(x);
		while (prev->next!= pos)
		{
			prev = prev->next;
		}
		newnode->next = pos;
		prev->next = newnode;
	}
}
cpp 复制代码
void SListEraseAfter(SListNode* pos)
{
	assert(pos && pos->next);
	SListNode* pcur = pos->next;
	pos->next = pcur->next;
	free(pcur);
	pcur = NULL;
}
cpp 复制代码
void SLTErase(SListNode** pphead, SListNode* pos)
{
	assert(pphead && *pphead && pos);
	if (pos == *pphead)
	{
		SListPopFront(pphead);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
	
}
void SLTDestroy(SListNode** pphead)
{
	assert(pphead);
	SListNode* pcur = *pphead;
	SListNode* prev = pcur;
	while (pcur)
	{
		pcur = pcur->next;
		free(prev);
		prev = pcur;
	}
	*pphead = NULL;
}
相关推荐
张张努力变强1 小时前
C++ STL string 类:常用接口 + auto + 范围 for全攻略,字符串操作效率拉满
开发语言·数据结构·c++·算法·stl
wWYy.1 小时前
数组快排 链表归并
数据结构·链表
李斯啦果2 小时前
【PTA】L1-019 谁先倒
数据结构·算法
Mr Xu_18 小时前
告别硬编码:前端项目中配置驱动的实战优化指南
前端·javascript·数据结构
czxyvX18 小时前
017-AVL树(C++实现)
开发语言·数据结构·c++
数智工坊18 小时前
【数据结构-队列】3.2 队列的顺序-链式实现-双端队列
数据结构
elseif12318 小时前
【C++】并查集&家谱树
开发语言·数据结构·c++·算法·图论
徐小夕@趣谈前端18 小时前
Web文档的“Office时刻“:jitword共建版2.0发布!让浏览器变成本地生产力
前端·数据结构·vue.js·算法·开源·编辑器·es6
Nebula_g19 小时前
线程进阶: 无人机自动防空平台开发教程(更新)
java·开发语言·数据结构·学习·算法·无人机
xuxie9920 小时前
day 23 树
数据结构