数据结构与算法——单链表(续)

news2025/5/17 16:18:30

单链表(续)

  • 查找
  • 在指定位置之前插入结点
  • 在指定位置之后插入结点
  • 删除pos位置的结点
  • 删除pos位置之后的结点
  • 销毁

查找

遍历:pcur指向头结点,循环,当pucr不为空进入循环,pucr里面指向的数据为要查找的值的时候就返回pcur否则将pucr下一个结点的地址赋值给pcur然后继续判断,直到找到值。如果为空直接返回。

函数的实现
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}
函数的测试运行
SLTNode* find = SLTFind(plist,2);
if (find)
{
	printf("找到了 \n");
}
else {
	printf("未找到 \n");
}

在这里插入图片描述
在这里插入图片描述

在指定位置之前插入结点

时间复杂度:O(N)

在这里插入图片描述
:头文件不能为空,也不能在空之前插入结点,首先要找到pos位置的前一个结点让它的next指针指向newnode,然后让newnode的next指针指向pos。如何找到pos的前一个结点?那就是遍历,从头结点开始,向后遍历,直到prev的next指针指向pos则就是pos的前一个结点。这里要注意,当pos为头结点的时候,执行的操作就变为了头插。

复习一下新结点的创建
SLTNode* SLTbuyNode(SLTDataType x)
{
	//根据x创建新结点
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}
复习一下头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTbuyNode(x);
	//链表为空和不为空一样
	newnode->next = *pphead;
	*pphead = newnode;
}
函数的实现
//在指定位置之前插入结点
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead && pos);//头结点不能为空,也不能在空之前插入结点
	//当pos为第一个结点的时候,实现的就是头插
	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else {
		// 实现代码
		SLTNode* newnode = SLTbuyNode(x);
		//找pos前一个结点
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = newnode;
		newnode->next = pos;
	}
}
函数的测试和运行
	SLTNode* find = SLTFind(plist,9);
	SLTInsert(&plist, find, 100);
	SLTPrint(plist);
}

在这里插入图片描述

在指定位置之后插入结点

时间复杂度:O(1)

在这里插入图片描述

1.newnode->next = pos->next         pos->next = newnode
2. pos->next = newnode              newnode->next = pos->next

两种方案是否都可行?答案是否定的。
看第二种方案,当pos->next = newnode后,newnode->next = pos->next就变成了newnode->next = newnode,所以只能用第一种方案。

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

因为仅仅根据pos就能够找到下一个结点,不需要遍历,所以只用传两个数据就可,而且当pos为尾结点时插入数据,这个代码也没问题,不需要像pos在头结点前插入时一样重新调用一下头插函数。

函数的测试和运行
void test02()
{
	//创建空链表
	SLTNode* plist = NULL; 
	//SLTPrint(plist);
	//SLTPushBack(&plist, 1); //plist是指向结点地址的指针,&plist则是指向结点地址指针的地址
	SLTPushFront(&plist, 1);
	SLTPushFront(&plist, 2);
	SLTPushFront(&plist, 3);
	SLTPushFront(&plist, 4);
	SLTPrint(plist);
	
	SLTNode* find = SLTFind(plist,1);
	SLTInsertAfter(find, 100);
	SLTPrint(plist);
}

在这里插入图片描述

删除pos位置的结点

时间复杂度:O(N)

在这里插入图片描述
这里还是通过遍历找到prev就是pos的前一个结点,然后让prev->next = pos->next,然后释放掉需要删除的那个结点
当pos为头结点的时候,通过遍历prev->next 并不能找不到pos,所以此时需要进行头删操作的引用

函数的实现
//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && pos);
	//pos为头结点的时候
	if (pos == *pphead)
	{
		//执行头删操作
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
复习一下头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* next = (*pphead)->next; //头结点的下一个结点存下来,然后将头结点删掉
	free(*pphead);
	*pphead = next;
}
函数的测试和运行
void test02()
{
	//创建空链表
	SLTNode* plist = NULL; 
	//SLTPrint(plist);
	//SLTPushBack(&plist, 1); //plist是指向结点地址的指针,&plist则是指向结点地址指针的地址
	SLTPushFront(&plist, 1);
	SLTPushFront(&plist, 2);
	SLTPushFront(&plist, 3);
	SLTPushFront(&plist, 4);
	SLTPrint(plist);
	
	SLTNode* find = SLTFind(plist,1);

	SLTErase(&plist, find);
	SLTPrint(plist);
}

在这里插入图片描述

删除pos位置之后的结点

时间复杂度:O(1)

在这里插入图片描述

三个结点都能够通过pos来找到,所以只需要一个参数,将pos->next改为pos->next->next,然后将pos->next这个结点释放掉。
思考:此时已经将pos的next指针修改了,已经指向“新结点”了,如图,该怎么释放掉需要删除的那个结点?
答案:定义一个del保存pos->next
但是当pos为尾结点的时候,pos->next为NULL,所以del->next是对空指针解引用就会报错,所以在assert里面再加入一个条件assert(pos && pos->next)

函数的实现
//删除pos之后结点
void SLTEraseAfter(SLTNode** pphead, SLTNode* pos)
{
	assert(pos && pos->next);
	SLTNode* del = pos->next;
	pos->next = del->next;//pos->next = pos->next->next
	free(del);
	del = NULL;
}
函数的测试和运行
void test02()
{
	//创建空链表
	SLTNode* plist = NULL; 
	//SLTPrint(plist);
	//SLTPushBack(&plist, 1); //plist是指向结点地址的指针,&plist则是指向结点地址指针的地址
	SLTPushFront(&plist, 1);
	SLTPushFront(&plist, 2);
	SLTPushFront(&plist, 3);
	SLTPushFront(&plist, 4);
	SLTPrint(plist);
	
	SLTNode* find = SLTFind(plist,2);
	
	SLTEraseAfter(find);
	SLTPrint(plist);
}

在这里插入图片描述

销毁

链表每个结点都是独立申请的,所以每个结点都需要一个一个的释放(free)掉,当我们从头结点先释放掉,我们先需要将下一个结点存起来,然后将头结点走到存着的这个结点,循环此操作直到free掉所有结点(走到为空)

函数的实现
//销毁链表
void SListDestroy(SLTNode** pphead)
{
	SLTNode* pcur = *pphead; //pcur从头结点开始走
	while (pcur)//不为空
	{
		SLTNode* next = pcur->next; //定义next储存pcur的下一个节点
		free(pcur);
		pcur = next;
	}
	*pphead = NULL; //手动置空,避免成为野指针
}
顺序表问题与思考:
中间/头部的插入删除,时间复杂度为O(N)                           链表头部插入删除O(1)

增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。          链表无需增容

增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200空间再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
                   
                                                           链表不存在空间的浪费

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

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

相关文章

全面且深度学习c++类和对象(上)

文章目录 过程和对象类的引入,类的定义类的访问限定符及封装类的访问限定符封装 类的实例化类大小内存对齐规则: this指针this特性 过程和对象 C语言面向过程设计,c面向对象设计, 举例:洗衣服 C语言:放衣服…

开源情报如何成为信息攻防的关键资源

相比于传统情报,开源情报具有情报数量大、情报质量好、情报成本低、情报可用性强等优势。这是开源情报能够成为信息攻防关键资源的主要原因。 海量信息让开源情报具有更大潜力。一是开源情报体量巨大。信息化时代是信息爆炸的时代,网络上发布的各种信息…

【风控】用户特征画像体系

一、体系架构概述 1.1 核心价值定位 风控特征画像体系是通过多维度数据融合分析,构建客户风险全景视图的智能化工具。其核心价值体现在: 全周期覆盖:贯穿客户生命周期的营销、贷前、贷中、贷后四大场景立体化刻画:整合基础数据…

Unity:场景管理系统 —— SceneManagement 模块

目录 🎬 什么是 Scene(场景)? Unity 项目中的 Scene 通常负责什么? 🌍 一个 Scene 包含哪些元素? Scene 的切换与管理 📁 如何创建与管理 Scenes? 什么是Scene Man…

SZU 编译原理

总结自 深圳大学《编译原理》课程所学相关知识。 文章目录 文法语法分析自顶向下的语法分析递归下降分析LL(1) 预测分析法FIRST 集合FOLLOW 集合 文法 乔姆斯基形式语言理论: 表达能力:0型文法 > 1型文法 > 2型文法 > 3型文法。 0 型文法&am…

【程序员AI入门:模型】19.开源模型工程化全攻略:从选型部署到高效集成,LangChain与One-API双剑合璧

一、模型选型与验证:精准匹配业务需求 (一)多维度评估体系 通过量化指标权重实现科学选型,示例代码计算模型综合得分: # 评估指标权重与模型得分 requirements {"accuracy": 0.4, "latency": …

ARM Cortex-M3内核详解

目录 一、ARM Cortex-M3内核基本介绍 (一)基本介绍 (二)主要组成部分 (三)调试系统 二、ARM Cortex-M3内核的内核架构 三、ARM Cortex-M3内核的寄存器 四、ARM Cortex-M3内核的存储结构 五、ARM Co…

ThinkStation图形工作站进入BIOS方法

首先视频线需要接在独立显卡上,重新开机,持续按F1,或者显示器出来lenovo的logo的时候按F1,这样就进到bios里了。联*想*坑,戴尔贵。靠。

go 集成base64Captcha 支持多种验证码

base64Captcha 是一个基于 Go 语言开发的验证码生成库,主要用于在 Web 应用中集成验证码功能,以增强系统的安全性。以下是其主要特点和简介: base64Captcha主要功能 验证码类型丰富:支持生成多种类型的验证码,包括纯…

【C语言字符函数和字符串函数(一)】--字符分类函数,字符转换函数,strlen,strcpy,strcat函数的使用和模拟实现

目录 一.字符分类函数 1.1--字符分类函数的理解 1.2--字符分类函数的使用 二.字符转换函数 2.1--字符转换函数的理解 2.2--字符转换函数的使用 三.strlen的使用和模拟实现 3.1--strlen的使用演示 3.2--strlen的返回值 3.3--strlen的模拟实现 四.strcpy的使用和模拟实现…

大模型基础之量化

概述 量化,Quantization,机器学习和深度学习领域是一种用于降低计算复杂度、减少内存占用、加速推理的优化方法。定义:将模型中的数据从高精度表示转换为低精度表示。主要目的是为了减少模型的存储需求和计算复杂度,同时尽量减少…

游戏引擎学习第286天:开始解耦实体行为

回顾并为今天的内容定下基调 我们目前正在进入实体系统的一个新阶段,之前我们已经让实体的移动系统变得更加灵活,现在我们想把这个思路继续延伸到实体系统的更深层次。今天的重点,是重新审视我们处理实体类型(entity type&#x…

win10-django项目与mysql的基本增删改查

以下都是在win10系统下,django项目的orm框架对本地mysql的表的操作 models.py----->即表对应的类所在的位置 在表里新增数据 1.引入表对应的在models.py中的类class 2.在views.py中使用函数:类名.objects.create(字段名值,字段名"值"。。。…

动态范围调整(SEF算法实现)

一、背景介绍 继续在整理对比度调整相关算法,发现一篇单帧动态范围提升的算法:Simulated Exposure Fusion,论文表现看起来很秀,这里尝试对它进行了下效果复现。 二、实现流程 1、基本原理 整体来说,大致可以分为两步…

SpringCloud微服务开发与实战

本节内容带你认识什么是微服务的特点,微服务的拆分,会使用Nacos实现服务治理,会使用OpenFeign实现远程调用(通过黑马商城来带你了解实际开发中微服务项目) 前言:从谷歌搜索指数来看,国内从自201…

WAS和Tomcat的对比

一、WAS和Tomcat的对比 WebSphere Application Server (WAS) 和 Apache Tomcat 是两款常用的 Java 应用服务器,但它们有许多显著的区别。在企业级应用中,它们扮演不同的角色,各自有其特点和适用场景。以下是它们在多个维度上的详细对比&…

IntelliJ IDEA打开项目后,目录和文件都不显示,只显示pom.xml,怎样可以再显示出来?

检查.idea文件夹 如果项目目录中缺少.idea文件夹,可能导致项目结构无法正确加载。可以尝试删除项目根目录下的.idea文件夹,然后重新打开项目,IDEA会自动生成新的.idea文件夹和相关配置文件,从而恢复项目结构。 问题解决&#xff0…

Hot100-链表-JS

160.相交链表 160. 相交链表 已解答 简单 相关标签 相关企业 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整…

事件驱动架构:从传统服务到实时响应的IT新风潮

文章目录 事件驱动架构的本质:从请求到事件的范式转变在EDA中: 事件驱动架构的演进:从消息队列到云原生标配核心技术:事件驱动架构的基石与工具链1. 消息队列:事件传递的枢纽2. 消费者:异步处理3. 事件总线…

网络流量分析 | NetworkMiner

介绍 NetworkMiner 是一款适用于Windows(也适用于Linux/Mac)的开源网络取证分析工具。它可被用作被动网络嗅探器/数据包捕获工具,也可被用于检测操作系统、会话、主机名、开放端口等,还能被用于解析pcap文件进行离线分析。点击此…