数据结构之单链表

一. 单链表定义(single linked list)

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

所谓单链表就是:单向链表 ,我们将链表中的每个元素称之为结点/节点单链表中的每个节点是单向的 ,也就是说,我们无法直接获得某一结点的前面的第一个结点,即:前驱结点。

二. 结构

链表是由一个个结点组成的

单链表是一种常见的数据结构,用于存储和操作一系列的数据。它由节点组成,每个节点包含数据和指向下一个节点的指针。

三. 链表的实现

1> 定义结点

typedef int SLTDateType;
typedef  struct SListNode
{
	SLTDateType Date;
	SListNode* next;
}SListNode;

2> 链表功能

//创建一个结点
SLTNode* BuyListNode(SLTDateType x);
//销毁单链表
void SLTDestory(SLTNode** pphead);
//单链表头插
void SLTPushFront(SLTNode** pphead, SLTDateType x);
//单链表尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x);
//单链表头删
void SLTPopFront(SLTNode** pphead);
//单链表尾删
void SLTPopBack(SLTNode** pphead);
//单链表结点查找
SLTNode* SLTNodeFind(SLTNode* phead, SLTDateType x);
//单链表结点删除(删除pos位置的结点)
void SLTErase(SLTNode** pphead, SLTNode* pos);
//单链表结点插入(在pos之前插入)
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);
// 单链表结点插入(在pos之后插入)
void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDateType x);
// 单链表结点修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDateType x);
//打印单链表
void PrintSLT(SLTNode * phead);

3> 链表功能的实现

#include"SLT.h"
 
//建立一个新的结点
//这是链表的缺点:经常需要使用malloc为newnode开辟空间
SLTNode* BuyListNode(SLTDateType x)
{
	//为什么要用malloc,是因为,如果在BuyListNode函数中SLTNode newnode,出了这个函数,newnode就被销毁了,
	//用malloc开辟空间,只要我们不主动释放这个空间,这个空间的数据一直存在,
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	//static SLTNode newnode;
	if (newnode == NULL)
	{
		perror("malloc:");
		exit(0);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
 
//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);//phead可能为NULL,但是pphead指向phead,不可能为空
	SLTNode* newnode = BuyListNode(x);
	//这里可不是newnode->next = (*pphead)->next;
	newnode->next = *pphead;
	*pphead = newnode;
}
 
 
//尾插
//尾插特别容易出错,当链表中没有数据,即phead=NULL时,尾插就相当于头插了,此时需要改变phead的值
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
	assert(pphead);
	SLTNode* newnode = BuyListNode(x);
	//1、空
	//2、非空
	if (*pphead == NULL)
	{
		*pphead = newnode;
		//newnode->next = NULL;这一步是不需要的,newnode在建立的时候就默认newnode->next=NULL;
	}
	else
	{
		SLTNode* cur = *pphead;
		//这是单向链表的缺点,需要去找尾
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}
}
 
//头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);
	//温柔的检查
	if (*pphead == NULL)
		return;
	//暴力的检查
	assert(*pphead);
	SLTNode* head = *pphead;
	*pphead = (*pphead)->next;
	free(head);
	head = NULL;
}
 
//尾删
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	//1、一个结点
	//2、两个结点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* cur = *pphead;
		while (cur->next->next)
		{
			cur = cur->next;
		}
		free(cur->next);
		cur->next = NULL;
	}
}
//打印单向链表
void PrintSLT(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL");
	printf("\n");
}
 
//单链表查找某个结点
SLTNode* SLTNodeFind(SLTNode* phead, SLTDateType x)
{
	SLTNode* find = phead;
	//别忘记分析找不到结点的情况
	while (find)
	{
		if (find->data == x)
		{
			return find;
		}
		find = find->next;
	}
	return NULL;
}
 
//删除pos位置的结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);
	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
			//如果prev->next已经为空了,说明链表已经查完了,还没有查到pos
			//证明pos传入有误
			assert(prev->next);
		}
		prev->next = pos->next;
		free(pos);
		//pos = NULL;这个没必要,改变不了pos
	}
}
//单链表结点前插
//一般插入结点都是在pos之前插入,但单链表在实现前插是比较困难的
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	assert(pphead);
	//头插
	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	//非头插
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
			assert(prev->next);
		}
		SLTNode* newnode = BuyListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}
//单链表结点后插
void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
	SLTNode* cur = *pphead;
	while (cur != pos)
	{
		cur = cur->next;
		//防止pos传错了
		assert(cur);
	}
	SLTNode* newnode = BuyListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}
 
// 单链表结点修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDateType x)
{
	SLTNode* cur = phead;
	while (cur != pos)
	{
		cur = cur->next;
		assert(cur);
	}
	pos->data = x;
}
//销毁链表
void SLTDestory(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* cur = *pphead;
	//比cur->next!=NULL更好一些
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

更加详细的请看原文【数据结构】------单链表超详细介绍(独家介绍,小白必看!!!)-CSDN博客


❤️❤️❤️

相关推荐
Hera_Yc.H2 小时前
数据结构之一:复杂度
数据结构
肥猪猪爸3 小时前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
linux_carlos3 小时前
环形缓冲区
数据结构
readmancynn4 小时前
二分基本实现
数据结构·算法
Bucai_不才4 小时前
【数据结构】树——链式存储二叉树的基础
数据结构·二叉树
盼海4 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步4 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
珹洺5 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
几窗花鸢5 小时前
力扣面试经典 150(下)
数据结构·c++·算法·leetcode
.Cnn5 小时前
用邻接矩阵实现图的深度优先遍历
c语言·数据结构·算法·深度优先·图论