数据结构—单链表

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

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

单链表的打印

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

单向/双向

循环/不循环

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

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

相关推荐
我命由我123452 小时前
Git 暂存文件警告信息:warning: LF will be replaced by CRLF in XXX.java.
java·linux·笔记·git·后端·学习·java-ee
greentea_20132 小时前
Codeforces Round 863 A. Insert Digit (1811)
数据结构·算法
lingggggaaaa3 小时前
小迪安全v2023学习笔记(九十五讲)—— 云原生篇&Docker安全&权限环境检测&容器逃逸&特权模式&危险挂载
笔记·学习·安全·web安全·网络安全·docker·云原生
Yupureki3 小时前
从零开始的C++学习生活 2:类和对象(上)
c语言·开发语言·c++·学习·visual studio
charlie1145141913 小时前
从《Life of A Pixel》来看Chrome的渲染机制
前端·chrome·学习·渲染·浏览器·原理分析
来不及辣哎呀3 小时前
学习Java第三十天——黑马点评37~42
java·开发语言·学习
半桶水专家4 小时前
C语言中的setitimer函数详解
c语言·开发语言·算法
-雷阵雨-4 小时前
数据结构——栈和队列(模拟实现)
java·开发语言·数据结构·intellij-idea
charlie1145141916 小时前
理解C++20的革命特性——协程支持1
c++·学习·c++20·协程·语言特性·调度·现代c++