数据结构:单链表

目录

1.1链表的概念

1.2单链表的结构

2.实现链表(不带头单向非循坏)

2.1链表结构的定义

2.2链表功能的实现

2.2.1动态申请一个结点

[2.2.2 打印单链表](#2.2.2 打印单链表)

2.2.3单链表头插

2.2.4单链表头删

2.2.5单链表查找

2.2.6单链表在pos位置之前插入

2.2.7删除pos位置

2.2.8销毁链表


1.1链表的概念

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

1.2单链表的结构

**注意:**最后一个结点的*next要等于NULL,next=NULL

2.实现链表(不带头单向非循坏)

2.1链表结构的定义
复制代码
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;
2.2链表功能的实现
复制代码
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);

// 单链表打印
void SListPrint(SListNode* plist);

// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);

// 单链表头删
void SListPopFront(SListNode** pplist);

// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);

//在pos的前面插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x);

// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos);
2.2.1动态申请一个结点

需要一个函数申请一个结点,方便后续的插入操作

复制代码
//动态申请一个节点
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* Node = (SListNode*)malloc(sizeof(SListNode));
	if (Node == NULL)
	{
		perror("Node::malloc");
		return NULL;
	}
	Node->data = x;
	Node->next = NULL;
	return Node;
}
2.2.2 打印单链表

打印链表就是遍历链表,当print = NULL时,停止打印

复制代码
// 单链表打印
void SListPrint(SListNode* plist)
{
	SListNode* print = plist;
	while (print != NULL)
	{
		printf("%d->", print->data);
		print = print->next;
	}

	printf("NULL\n");
}
2.2.3单链表头插

单链表头插十分简单,只需要将新结点 的next指向单链表第一个结点,然后将原来单链表指向新结点即可。

复制代码
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
	SListNode* Node = BuySListNode(x);
	Node->next = *pplist;
	*pplist = Node;
}
2.2.4单链表头删

头删也是十分简单,首先找到原链表首结点的下一个结点,然后释放掉第一个结点。

复制代码
// 单链表头删
void SListPopFront(SListNode** pplist)
{
	assert(*pplist);
	SListNode* FrontDele = *pplist;
	*pplist = FrontDele->next;
	free(FrontDele);
	FrontDele = NULL;
}
2.2.5单链表查找

找到该数据,返回该数据所在位置的地址(即结点),找不到返回NULL

复制代码
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
	assert(plist);
	SListNode* find = plist;
	while (find != NULL)
	{
		if (find->data == x)
		{
			return find;
		}
		find = find->next;
	}

	//当找不到返回NULL
	
	return NULL;
}
2.2.6单链表在pos位置之前插入
复制代码
// 在pos的前面插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x)
{
	assert(pplist);
	assert(pos);
	
	
	SListNode* Node = BuySListNode(x);
	SListNode* Insert = *pplist;
   //当Ineset的下一个结点为空,则代表链表只有一个结点,所以直接头插
	if (Insert->next == NULL)
	{
		SListPushFront(pplist, x);
	}
	else
	{
      //找到pos前面的结点的位置
		while (Insert->next != pos)
		{
			Insert = Insert->next;

		}
    //找到后将新结点的next指向pos,然后pos前面结点的位置指向新结点
		Node->next = Insert->next;
		Insert->next = Node;
	}
	
}
2.2.7删除pos位置
复制代码
// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos)
{
	assert(pplist);
	assert(pos);
	
	SListNode* Erase = *pplist;
  //找到pos前面结点的位置
	while (Erase->next != pos)
	{
		Erase = Erase->next;
	}
	
	//然后将Erase的next指向pos下一个结点
	Erase->next = pos->next;
	free(pos);
	pos = NULL;
}
2.2.8销毁链表

链表是由一个个结点组成,每个结点都动态申请了空间,所以销毁链表需要遍历,然后一个一个释放掉

复制代码
//销毁链表
void SLTDestory(SListNode** pphead)
{
	assert(pphead);
	SListNode* cur = *pphead;
	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

最后需要注意的是:

调用链表的各个函数时需要传二级指针 ,如果传一级指针则会出现很多问题 ,因为链表功能的实现是在函数里改变了指针,这里只是形参 的改变,并没有给实参带来变化,所以想要实参变化必须使用二级指针!!!

相关推荐
CSharp精选营4 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假8 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠9 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦15 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠16 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾16 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82116 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q17 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒17 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记17 天前
单项不带头不循环链表
数据结构·链表