数据结构—单链表

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

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

单链表的打印

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不表示头节点,表示第一个有效的节点。

单向/双向

循环/不循环

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

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

相关推荐
CSharp精选营2 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假6 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠7 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦13 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
通信小呆呆14 天前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
H__Rick14 天前
自动对焦学习-3
人工智能·学习·计算机视觉
Daisy Lee14 天前
量化学习-第1章-什么是量化金融
学习·金融·datawhale
小小工匠14 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
Luminous.14 天前
C语言--day30
c语言·开发语言