数据结构—单链表

单链表在物理空间上非线性的,相对于顺序表更加节省空间。

链表由一个一个的节点组成,每一个节点储存着数据和指向下一节点的指针,所以链表在逻辑上是线性的。

单链表的打印

cpp 复制代码
void SLTPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		printf(" %d ->", pcur->data);
		pcur = pcur->next;
	}
	printf(" NULL");
}

这里由于不需要对结构体进行修改所以传递一级指针

在单链表中插入数据

设置结点

cpp 复制代码
SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode SList;
	SLTNode* tmp = (SLTNode*)malloc(sizeof(SList));
	if (tmp == NULL)
	{
		perror("SLTBuyNode");
		exit(1);
	}
	tmp->data = x;
	tmp->next = NULL;
	return tmp;
}

在单链表尾部插入数据

cpp 复制代码
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* tmp = SLTBuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = tmp;
	}
	else
	{
		SLTNode* ptr = *pphead;
		while (ptr->next)
		{
			ptr = ptr->next;
		}
		ptr->next = tmp;
	}
}

在单链表头部插入数据

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

在单链表指定位置之前插入数据

cpp 复制代码
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && *pphead&&pos);
	SLTNode* tmp = SLTBuyNode(x);
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev -> next;
		}
		prev->next = tmp;
		tmp->next = pos;
	}
}

在单链表指定位置之后插入数据

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

删除单链表的数据

删除单链表尾部的数据

cpp 复制代码
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* prev = *pphead;
		SLTNode* ptr = *pphead;
		while (ptr->next)
		{
			prev = ptr;
			ptr = ptr->next;
		}
		free(ptr);
		ptr = NULL;
		prev->next = NULL;
	}
}

删除单链表头部的数据

cpp 复制代码
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead&&*pphead);
	SLTNode* tmp = NULL;
	tmp = (*pphead)->next;
	free(*pphead);
	*pphead = tmp;
}

删除单链表指定位置的数据

cpp 复制代码
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead&&pos);
	if (pos==*pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* tmp = *pphead;
		while (tmp->next != pos)
		{
			tmp = tmp->next;
		}
		tmp->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

删除单链表指定位置之后的数据

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

查找单链表中的数据

cpp 复制代码
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	assert(phead);
	SLTNode* ptr = phead;
	while (ptr)
	{
		if (ptr->data == x)
			return ptr;
		else
			ptr = ptr->next;
	}
	return NULL;
}

单链表的销毁

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

链表的分类

链表的结构非常多样,以下情况总结起来就有八种链表结构

带头

链表中有哨兵位节点,该哨兵位节点就是头节点。上文实现的链表中phead不表示头节点,表示第一个有效的节点。

单向/双向

循环/不循环

前面实现的链表就是不带头不循环 的单向链表,简称单链表

还有一个经常使用的链表就是带头循环 双向链表,简称双向链表

相关推荐
李斯啦果7 分钟前
【PTA】L1-019 谁先倒
数据结构·算法
晓131310 分钟前
第七章 【C语言篇:文件】 文件全面解析
linux·c语言·开发语言
梵刹古音13 分钟前
【C语言】 指针基础与定义
c语言·开发语言·算法
ZH154558913114 分钟前
Flutter for OpenHarmony Python学习助手实战:Web开发框架应用的实现
python·学习·flutter
百锦再27 分钟前
Vue高阶知识:利用 defineModel 特性开发搜索组件组合
前端·vue.js·学习·flutter·typescript·前端框架
CappuccinoRose1 小时前
JavaScript 学习文档(二)
前端·javascript·学习·数据类型·运算符·箭头函数·变量声明
A9better1 小时前
C++——不一样的I/O工具与名称空间
开发语言·c++·学习
杜子不疼.1 小时前
Ascend_C自定义算子开发
c语言·开发语言
小乔的编程内容分享站1 小时前
C语言笔记之函数
c语言·笔记
AI职业加油站1 小时前
职业提升之路:我的大数据分析师学习与备考分享
大数据·人工智能·经验分享·学习·职场和发展·数据分析