【零基础学数据结构】链表

news2024/11/25 2:53:59

 

目录

1.链表的概念

​编辑 2.链表的雏形

​编辑 3.链表的组成

​编辑 4.链表代码

 4.1创建节点

 4.2链表的打印

 4.3链表的尾插

 4.4链表的头插

 4.5链表的尾删

 4.6链表的头删

 4.7链表的查找

 4.8链表在指定位置之前插⼊数据

 4.9链表在指定位置之后插⼊数据

 4.9-1删除pos节点

 4.9-2删除pos之后的节点

4.9-3销毁链表

补充:测试文件:


1.链表的概念

 2.链表的雏形

 3.链表的组成

 4.链表代码

 创建准备;

  • SListNode.h文件
  • SListNode.c文件
  • text.c文件 

 4.1创建节点

 数据+指向下一个节点的指针

// 首先定义数据的类型,方便后续更改
typedef int SLTNodeDataType;

// 创建节点
typedef struct SListNode
{
	SLTNodeDataType data; // 存储数据
	struct SListNode* next;// 指向下一个节点的指针
}SLTNode;

 4.2链表的打印

 头文件声明:

void SLTPrint(SLTNode* phead);

执行文件代码实现: 

// 链表的打印
void SLTPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;// 保证phead指向的位置是收节点,方便后续再次遍历
	while (pcur)// 等价于 pcur != NULL;
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}

 4.3链表的尾插

 头文件声明:

void SLTPushBack(SLTNode** pphead, SLTNodeDataType x);
// 创建新的节点
SLTNode* SLTBuyNode(SLTNodeDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (NULL == newnode)
	{
		perror("SLTBuyNode malloc err!");
		exit(1);
	}

	// 创建节点成功
	newnode->data = x;
	newnode->next = NULL;

	// 返回
	return newnode;
}

 执行文件代码实现: 

// 链表的尾插
void SLTPushBack(SLTNode** pphead, SLTNodeDataType x)
{
	// 传参不可为空
	assert(pphead);

	// 创建一个新的节点
	SLTNode* newnode = SLTBuyNode(x);

	// 空链表和非空链表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{

		// 找尾巴
		SLTNode* ptail = *pphead;
		while (ptail->next) // 等价于ptail->next !=NULL;
		{
			ptail = ptail->next;
		}

		// 找到尾巴,开始连接
		ptail->next = newnode;
	}
	
}

 4.4链表的头插

  头文件声明:

// 链表的头插
void SLTPushFront(SLTNode** pphead, SLTNodeDataType x);

 执行文件代码实现:

// 链表的头插
void SLTPushFront(SLTNode** pphead, SLTNodeDataType x)
{
	// 传参不可为空
	assert(pphead);

	// 创建一个新的节点
	SLTNode* newnode = SLTBuyNode(x);

	// 头插
	newnode->next = *pphead;
	*pphead = newnode;
}

 4.5链表的尾删

 头文件声明:

void SLTPopBack(SLTNode** pphead);

  执行文件代码实现:

// 链表的尾删
void SLTPopBack(SLTNode** pphead)
{
	// 链表不可以为空,传参不可为空
	assert(pphead && *pphead);

	// 链表有一个节点和多个节点
	// 一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else //多个节点
	{
		// 找尾
		SLTNode* prev = *pphead;
		SLTNode* ptail = *pphead;

		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}

		free(ptail); // 释放空间
		ptail = NULL;// 防止野指针
		prev->next = NULL;
	}
	
}

 4.6链表的头删

 头文件声明:

void SLTPopFront(SLTNode** pphead);

   执行文件代码实现:

// 链表的头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

 4.7链表的查找

 头文件声明:

SLTNode* SLTFind(SLTNode* phead, SLTNodeDataType x);

 执行文件代码实现:

// 链表的查找
SLTNode* SLTFind(SLTNode* phead, SLTNodeDataType x)
{
	
	SLTNode* prev = phead;
	while (prev)// 等价于 prev != NULL;
	{
		if (prev->data == x)
		{
			return prev;
		}
		prev = prev->next;
	}

	// 遍历完毕没有找到,返回空。
	return NULL;
}

 4.8链表在指定位置之前插⼊数据

 头文件声明:

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTNodeDataType x);

 执行文件代码实现:

// 链表在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTNodeDataType x)
{
	// 不可以传入NULL
	assert(pphead && *pphead);
	assert(pos);

	// 创建一个新的节点
	SLTNode* newnode = SLTBuyNode(x);

	// 如果节点只有一个,就是头插
	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* pcur = *pphead;

		// pcur所指向的节点不为pos前一个节点
		while (pcur->next != pos)
		{
			pcur = pcur->next;
		}

		// pcur所指向的节点为pos前一个节点
		newnode->next = pos;
		pcur->next = newnode;
	}
}

 4.9链表在指定位置之后插⼊数据

  头文件声明:

void SLTInsertAfter(SLTNode* pos, SLTNodeDataType x);

 执行文件代码实现:

// 链表在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTNodeDataType x)
{
	assert(pos);

	// 创建要插入的节点
	SLTNode* newnode = SLTBuyNode(x);

	// 开始插入
	newnode->next = pos->next;
	pos->next = newnode;
}

 4.9-1删除pos节点

 头文件声明:

void SLTErase(SLTNode** pphead, SLTNode* pos);

  执行文件代码实现:

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;

		while (prev->next != pos)
		{
			prev = prev->next;
		}

		// prev所指向的就是pos前一个节点
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}

}

 4.9-2删除pos之后的节点

 头文件声明:

void SLTEraseAfter(SLTNode* pos);

 执行文件代码实现:

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos && pos->next); // 传过来的参数不可以为空,pos下一个的参数也不可以是NULL

	SLTNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}

4.9-3销毁链表

 文件声明:

void SListDesTroy(SLTNode** pphead);

 执行文件代码实现:

//销毁链表
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	// 全部销毁完后,置为空NULL;
	*pphead = NULL;
}

补充:测试文件:

//void SListNodeText01()
//{
//	// 创建节点
//	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
//	node1->data = 1;
//
//	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
//	node2->data = 2;
//
//	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
//	node3->data = 3;
//
//	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
//	node4->data = 4;
//
//	// 将四个节点连接起来
//	node1->next = node2;
//	node2->next = node3;
//	node3->next = node4;
//	node4->next = NULL;
//
//	// 打印
//	SLTPrint(node1);
//}

void SLTNodeText02()
{
	//SLTNode* plist = NULL;

	// 测试尾插
	//SLTPushBack(&plist, 1);
	//SLTPushBack(&plist, 2);
	//SLTPushBack(&plist, 3);
	//SLTPushBack(&plist, 4);
	/*SLTPrint(plist);*/// 1->2->3->4->NULL;


	// 测试头插
	/*SLTPushFront(&plist, 5);
	SLTPrint(plist);

	SLTPushFront(&plist, 6);
	SLTPrint(plist);

	SLTPushFront(&plist, 7);
	SLTPrint(plist);

	SLTPushFront(&plist, 8);
	SLTPrint(plist);*/


    // 测试尾删
	//SLTPopBack(&plist);
	//SLTPrint(plist);
	//SLTPopBack(&plist);
	//SLTPrint(plist);
	//SLTPopBack(&plist);
	//SLTPrint(plist);
	//SLTPopBack(&plist);
	//SLTPrint(plist);


	// 测试头删
	//SLTPopFront(&plist);
	//SLTPrint(plist);
	//SLTPopFront(&plist);
	//SLTPrint(plist);
	//SLTPopFront(&plist);
	//SLTPrint(plist);
	//SLTPopFront(&plist);
	//SLTPrint(plist);
	// 报错
	//SLTPopFront(&plist);
	//SLTPrint(plist);


	// 测试查找
	//SLTNode* find = SLTFind(plist, NULL);
	//if (find == NULL)
	//{
	//	printf("没有找到!\n");
	//}
	//else
	//{
	//	printf("找到了!\n");
	//}


	// 测试在pos位置之前插⼊数据
	//SLTNode* find = SLTFind(plist, 1);
	//SLTInsert(&plist, find, 11);
	//SLTPrint(plist);


	// 测试链表在指定位置之后插⼊数据
	/*SLTNode* find = SLTFind(plist, 4);
	SLTInsertAfter(find, 11);
	SLTPrint(plist);*/

	// 测试删除pos之后的节点
	/*SLTNode* find = SLTFind(plist, 1);
	SLTEraseAfter(find);
	SLTPrint(plist);*/

	// 测试销毁
	SListDesTroy(&plist);
}

int main()
{
	//SListNodeText01();
	SLTNodeText02();
	return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1580611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VBA技术资料MF140:在PowerPoint中移动幻灯片位置

我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…

Java基于微信小程序的校园外卖平台设计与实现,附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警

文章目录 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 Plan Hint的结果会体现在计划的变化上,可以通过explain来查看变化。 …

公开课学习——JVM虚拟机面试核心点与性能优化点

文章目录 jdk的体系结构图Java语言的跨平台的特性,怎么实现的?jvm内部组成呢?pc的值怎么变得?main方法的栈帧有一点点区别,Math()是new出来的,放在堆区,这个堆区的math和我们栈帧中的局部变量表…

SpringBoot之集成Redis

SpringBoot之集成Redis 一、Redis集成简介二、集成步骤2.1 添加依赖2.2 添加配置2.3 项目中使用 三、工具类封装四、序列化 (正常都需要自定义序列化)五、分布式锁 一、Redis集成简介 Redis是我们Java开发中,使用频次非常高的一个nosql数据库…

【频繁模式挖掘】Apriori算法(附Python实现)

一、实验内容简介 该实验主要使用频繁模式和关联规则进行数据挖掘,使用Apriori算法和Python语言来编写和设计程序,然后用不同规模的数据集来检验效果,最后分析和探讨实验结果,看其是否达到了理想的效果。 二、算法说明 关联规则…

2024年生成式人工智能的现状:进展、挑战与未来展望的深入分析

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

wireshark抓包新手使用教程

Wireshark是非常流行的网络封包分析软件,可以截取各种网络数据包,并显示数据包详细信息。常用于开发测试过程各种问题定位。本文主要内容包括: 1、Wireshark软件下载和安装以及Wireshark主界面介绍。 2、WireShark简单抓包示例。通过该例子学…

【C++航海王:追寻罗杰的编程之路】探寻实用的调试技巧

目录 1 -> 什么是bug? 2 -> 调试是什么?有多重要? 2.1 -> 调试是什么? 2.2 -> 调试的基本步骤 2.3 -> Debug和Release的介绍 3 -> Windows环境调试介绍 3.1 -> 调试环境的准备 3.2 -> 学会快捷键…

不牺牲算法,不挑剔芯片,这个来自中科院的团队正在加速国产AI芯片破局

ChatGPT狂飙160天,世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 不降低大模型算法精度,还能把芯片的算力利用效率提升 2~10 倍,这就是…

java swing毕业设计题目管理系统eclipse开发Mysql数据库CS结构java编程

一、源码特点 java swing毕业设计题目管理系统 是一套完善的窗体设计系统,对理解SWING java 编程开发语言有帮助,系统具有完整的源代码和数据库,,系统主要采用C/S模式开发。 应用技术:javamysql 开发工具&#xff…

杨笛一新作:社恐有救了,AI大模型一对一陪聊,帮i人变成e人

ChatGPT狂飙160天,世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站ai人工智能工具 更多资源欢迎关注 在社交活动中,大语言模型既可以是你的合作伙伴(partner)&#xff0…

SSL证书价格为什么差异如此大?

SSL证书市场品牌和种类众多,用户在选择证书的时候,也能随心所欲的购买到心仪的证书品牌类型。但是也有不少用户在选购的时候,也不禁有疑问:不同的证书品牌和类型为什么价格相差如此之大?确实,有的证书很便宜…

重磅来袭!2024CWE北京门窗幕墙展

CWE中国(北京)国际系统门窗及幕墙博览会 CWE China(Beijing)International System Doors Windows and Curtain Walls Expo 2024 年 8 月 29-31 日 北京,中国国际展览中心顺义馆 展会概况: 2024年CWE中国…

低代码开发平台推荐:国内超好用的十款实测评测

随着互联网技术的飞速发展,低代码平台逐渐成为企业数字化转型的利器。这类平台简化了开发过程,让非专业开发者也能参与到应用构建中来。本文将为您盘点国内十大低代码平台有:Zoho creator、,帮助您更好地选择适合自己企业的低代码…

【目标检测】-入门知识

1、回归与分类问题 回归问题是指给定输入变量(特征)和一个连续的输出变量(标签),建立一个函数来预测输出变量的值。换句话说,回归问题的目标是预测一个连续的输出值,例如预测房价、股票价格、销售额等。回归问题通常使用回归分析技术,例如线性回归、多项式回归、决策树…

Win10系统下的EDGE浏览器启用IE模式

Win10系统下的EDGE浏览器目前已弃用IE内核,这样在访问某些较老的网站会有兼容性问题,本文记录了在EDGE浏览器中启用IE模式的操作方法。 一、启用EDGE浏览器的IE模式 要打开Internet Explorer模式,执行以下步骤: 1、在Microsoft Edge的地址栏…

同城O2O:开发外卖跑腿小程序的技术探索

当下,开发一款功能完善、用户体验良好的外卖跑腿小程序成为了很多互联网企业的首要任务。今天小编将从技术角度对开发外卖跑腿小程序进行探索,为开发者提供一些技术上的思路和方法。 1.技术选型 在开发外卖跑腿小程序时,选择合适的技术栈至关…

Docker使用— Docker部署安装Nginx

Nginx简介 Nginx 是一款高性能的 web 服务器、反向代理服务器以及电子邮件(IMAP/POP3/SMTP)代理服务器,由俄罗斯开发者伊戈尔塞索耶夫(Igor Sysoev)编写,并在2004年10月4日发布了首个公开版本0.1.0。Nginx…

C++--运算符重载

运算符重载 在类中重新定义运算符,赋予运算符新的功能以适应类的运算,就称为运算符重载。 运算符重载是一种形式的C多态,它使得对象操作更直观,本质上也是属于函数重载。 实际上,我们已经在不知不觉之中使用了运算符重载。例如,加…