【数据结构】单链表专题-->单链表实现(附:全部码源)

🔥 博客主页🔥 :【 坊钰_CSDN博客

欢迎各位点赞👍 评论**✍收藏⭐**

目录

[1. 链表的概念及结构](#1. 链表的概念及结构)

[2. 预前准备](#2. 预前准备)

[2.1 分文件存放](#2.1 分文件存放)

[3. 单链表的实现](#3. 单链表的实现)

[3.1 定义节点](#3.1 定义节点)

[3.2 尾插和头插](#3.2 尾插和头插)

[3.2.1 尾插](#3.2.1 尾插)

[3.2.2 头插](#3.2.2 头插)

[3.3 节点申请空间和打印](#3.3 节点申请空间和打印)

[3.3.1 节点申请空间](#3.3.1 节点申请空间)

[3.3.2 打印](#3.3.2 打印)

[3.4 尾删和头删](#3.4 尾删和头删)

[3.4.1 尾删](#3.4.1 尾删)

[3.4.2 头删](#3.4.2 头删)

[3.5 在指定位置(前/后)插入数据](#3.5 在指定位置(前/后)插入数据)

[3.5.1 在指定位置之后插入数据](#3.5.1 在指定位置之后插入数据)

[3.5.2 在指定位置之前插入数据](#3.5.2 在指定位置之前插入数据)

[3.6 查找](#3.6 查找)

[3.7 删除查找节点和链表销毁](#3.7 删除查找节点和链表销毁)

[3.7.1 删除查找节点](#3.7.1 删除查找节点)

[3.7.2 销毁链表](#3.7.2 销毁链表)

[4. 全部码源](#4. 全部码源)

[4.1 文件](#4.1 文件)

[4.2 文件](#4.2 文件)

[4.3 test.c文件](#4.3 test.c文件)

[5. 运行效果](#5. 运行效果)

[6. 小结](#6. 小结)


1. 链表的概念及结构

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

链表的结构跟火车车厢相似,在链表⾥,每节"⻋厢"是什么样的呢?

  1. 与顺序表不同的是,链表⾥的每节"⻋厢"都是独⽴申请下来的空间,我们称之为"结点/节点"
  2. 节点的组成主要有两个部分:当前节点要保存的数据和保存下⼀个节点的地址(指针变量)
  3. 图中指针变量plist保存的是第⼀个节点的地址,我们称plist此时"指向"第⼀个节点,如果我们希 望plist"指向"第⼆个节点时,只需要修改plist保存的内容为0x0012FFA0;

结合前⾯学到的结构体知识,我们可以给出每个节点对应的结构体代码:

假设当前保存的节点为整型:

cs 复制代码
struct SListNode
{
 int data; //节点数据 
 struct SListNode* next; //指针变量⽤保存下⼀个节点的地址 
};

给定的链表结构中,如何实现节点从头到尾的打印?

思考:当我们想保存的数据类型为字符型、浮点型或者其他⾃定义的类型时,该如何修改?

补充说明:

  1. 链式机构在逻辑上是连续的,在物理结构上不⼀定连续
  2. 节点⼀般是从堆上申请的
  3. 从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

2. 预前准备

2.1 分文件存放

cs 复制代码
Slist.h    ----------->单链表结构及函数声明
Slist.c    ----------->单链表的函数实现
test.c    -------------->代码测试

3. 单链表的实现

3.1 定义节点

cs 复制代码
//定义节点结构

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

3.2 尾插和头插

3.2.1 尾插

cs 复制代码
//尾插实现
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = SLTBuyNode(x);
	assert(pphead);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
	SLTNode* pure = *pphead;
		while (pure->next)
		{
			pure = pure->next;
		}
		pure->next = newnode;
	}
}

3.2.2 头插

cs 复制代码
//头插实现
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

3.3 节点申请空间和打印

3.3.1 节点申请空间

cs 复制代码
//节点申请空间实现
SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc");
		return 0;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

3.3.2 打印

cs 复制代码
//打印实现
void SLTPrin(SLTNode* phead)
{
	SLTNode* pure = phead;
	while (pure)
	{
		printf("%d->", pure->data);
		pure = pure->next;
	}
	printf("NULL\n");
}

3.4 尾删和头删

3.4.1 尾删

cs 复制代码
//尾删实现
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead&&*pphead);
	if ((*pphead)->next==NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
	SLTNode* pure = *pphead;
		SLTNode* cure = *pphead;
		while (cure->next)
		{
			pure = cure;
			cure = cure->next;
		}
		pure->next = NULL;
		free(cure);
		cure = NULL;
	}
}

3.4.2 头删

cs 复制代码
//头删实现
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pure = (*pphead)->next;
	free(*pphead);
	*pphead = pure;
}

3.5 在指定位置(前/后)插入数据

3.5.1 在指定位置之后插入数据

cs 复制代码
//在指定位置之后插入数据实现
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

3.5.2 在指定位置之前插入数据

cs 复制代码
//在指定位置之前插入数据实现
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && *pphead && pos);
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* newnode = SLTBuyNode(x);
		SLTNode* pure = *pphead;
		while (pure->next != pos)
		{
			pure = pure->next;
		}
		pure->next = newnode;
		newnode->next = pos;
	}
}

3.6 查找

cs 复制代码
//查找实现
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* pure = phead;
	while (pure)
	{
		if (pure->data == x)
		{
			return pure;
		}
		pure = pure->next;
	}
	return NULL;
}

3.7 删除查找节点和链表销毁

3.7.1 删除查找节点

cs 复制代码
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead && pos);
	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* pure = *pphead;
		while (pure->next != pos)
		{
			pure = pure->next;
		}
		pure->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

3.7.2 销毁链表

cs 复制代码
//销毁链表实现
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pure = *pphead;
	while (pure)
	{
		SLTNode* next = pure->next;
		free(pure);
		pure = next;
	}
	*pphead = NULL;
}

4. 全部码源

4.1 <Slist.h>文件

<Slist.h>文件

cs 复制代码
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLTDataType;

//定义节点结构
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

//节点申请空间
SLTNode* SLTBuyNode(SLTDataType x);

//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);

//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);

//打印
void SLTPrin(SLTNode* phead);

//尾删
void SLTPopBack(SLTNode** pphead);

//头删
void SLTPopFront(SLTNode** pphead);

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);

//销毁链表
void SListDesTroy(SLTNode** pphead);

4.2 <Slist.c>文件

<Slist.c>文件

cs 复制代码
#include "Slist.h"


//节点申请空间实现
SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc");
		return 0;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

//尾插实现
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = SLTBuyNode(x);
	assert(pphead);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
	SLTNode* pure = *pphead;
		while (pure->next)
		{
			pure = pure->next;
		}
		pure->next = newnode;
	}
}

//头插实现
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

//打印实现
void SLTPrin(SLTNode* phead)
{
	SLTNode* pure = phead;
	while (pure)
	{
		printf("%d->", pure->data);
		pure = pure->next;
	}
	printf("NULL\n");
}

//尾删实现
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead&&*pphead);
	if ((*pphead)->next==NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
	SLTNode* pure = *pphead;
		SLTNode* cure = *pphead;
		while (cure->next)
		{
			pure = cure;
			cure = cure->next;
		}
		pure->next = NULL;
		free(cure);
		cure = NULL;
	}
}

//头删实现
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pure = (*pphead)->next;
	free(*pphead);
	*pphead = pure;
}

//查找实现
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* pure = phead;
	while (pure)
	{
		if (pure->data == x)
		{
			return pure;
		}
		pure = pure->next;
	}
	return NULL;
}

//在指定位置之前插入数据实现
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && *pphead && pos);
	if (*pphead == pos)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* newnode = SLTBuyNode(x);
		SLTNode* pure = *pphead;
		while (pure->next != pos)
		{
			pure = pure->next;
		}
		pure->next = newnode;
		newnode->next = pos;
	}
}

//在指定位置之后插入数据实现
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead && pos);
	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* pure = *pphead;
		while (pure->next != pos)
		{
			pure = pure->next;
		}
		pure->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

//销毁链表实现
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pure = *pphead;
	while (pure)
	{
		SLTNode* next = pure->next;
		free(pure);
		pure = next;
	}
	*pphead = NULL;
}

4.3 test.c文件

test.c文件

cs 复制代码
#include "Slist.h"


void SLTCheek()
{
	SLTNode* slist = NULL;
	//尾插
	printf("插入1~6\n");
	SLTPushBack(&slist, 1);
	SLTPushBack(&slist, 2);
	SLTPushBack(&slist, 3);
	SLTPushBack(&slist, 4);
	SLTPushBack(&slist, 5);
	SLTPushBack(&slist, 6);
	SLTPrin(slist);

	打印
	//SLTPrin(slist);

	//头插
	printf("头插入100\n");
	SLTPushFront(&slist, 100);
	SLTPrin(slist);

	//尾删
	printf("尾部删除\n");
	SLTPopBack(&slist);
	SLTPrin(slist);

	//头删
	printf("头部删除\n");
	SLTPopFront(&slist);
	SLTPrin(slist);

	//查找
	SLTNode* find = SLTFind(slist, 3);

	//在指定位置之前插入数据
	printf("在3之前插入数据99\n");
	SLTInsert(&slist, find, 99);
	SLTPrin(slist);

	//在指定位置之后插入数据
	printf("在3之后插入数据100\n");
	SLTInsertAfter(find, 100);
	SLTPrin(slist);

	//删除pos点
	printf("删除3的节点\n");
	SLTErase(&slist,find);
	SLTPrin(slist);

	//销毁
	SListDesTroy(&slist);
}

int main()
{
	SLTCheek();
	return 0;
}

5. 运行效果

6. 小结

以上就是关于单链表的内容了,具体还需宝子们去实践,如果觉得该博客对你有用的话,希望一键三连,点个关注不迷路,谢谢支持!

相关推荐
徐浪老师43 分钟前
C语言实现冒泡排序:从基础到优化全解析
c语言·算法·排序算法
李小白661 小时前
各种排序算法
数据结构·算法·排序算法
浪前1 小时前
排序算法之冒泡排序篇
数据结构·算法·排序算法
是糖不是唐1 小时前
代码随想录算法训练营第五十八天|Day58 图论
c语言·算法·图论
一尘之中2 小时前
使用 PyTorch TunableOp 加速 ROCm 上的模型
人工智能·pytorch·学习
honey ball2 小时前
LLC与反激电路设计【学习笔记】
单片机·嵌入式硬件·学习
羚羊角uou4 小时前
【C++】list模拟实现(详解)
开发语言·c++
Peter_chq4 小时前
【计算机网络】多路转接之select
linux·c语言·开发语言·网络·c++·后端·select
如生命般费解的谜团5 小时前
LLM学习笔记(7)Scaled Dot-product Attention
人工智能·笔记·学习·语言模型·json