数据结构—单链表

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

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

单链表的打印

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

单向/双向

循环/不循环

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

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

相关推荐
y = xⁿ3 小时前
DeepSeek Harness 学习日记:关于Agent接口,工具调用的底层实现
android·java·学习
AI情绪识别开源5 小时前
检信 ALLEMOTION OS 加密打包可执行程序 — 全面测试报告版本: v1.3功能测试 / 性能测试 /
开发语言·数据结构·人工智能·功能测试
HugoStudio_SWAN7 小时前
【擦除重绘】C++ 控制台动画:弹跳 Logo DVD 屏保效果
开发语言·c++·学习·程序人生
sakiko_8 小时前
Swift学习笔记42-SwiftUI的属性包装器(讲解+面试)
笔记·学习·ios·swiftui·swift
Brilliantwxx9 小时前
【C语言】 初入嵌入式C语言复习(基础+进阶面试题)
c语言·开发语言
wuminyu10 小时前
深入剖析 Panama Off-heap 的性能损耗与开销
java·linux·c语言·jvm·c++
存在morning10 小时前
【Paimon 学习笔记 三】工作流程:Paimon 的批写、流写、批读与流读
笔记·学习
rhythm-ring10 小时前
宏定义续行符 \ 的使用与踩坑
c语言·c++
老当益壮梁奶奶11 小时前
Linux软件编程学习笔记(八):进程间通信详解(1)
linux·c语言·笔记·学习·算法
「QT(C++)开发工程师」11 小时前
C++11 std::unique_ptr — 独占所有权的智能指针
c语言·开发语言·c++·qt