《算法笔记》总结No.10——链表

news2024/12/23 12:20:36

        从第10期破例插叙一期单链表的实现,这个东东相当重要!考研的同学也可以看:相较于王道考研的伪码不太相同,专注于可以运行。如果是笔试中的伪码,意思正确即可~

 注:博主之前写过一个版本的顺序表和单链表的C++实现,和这篇的写法有所不同,不过内容也较全,大家可以先行阅读~C++数据结构笔记(2)线性表的顺序存储和链式存储_c++线性表的顺序存储和链式存储-CSDN博客文章浏览阅读348次。1.线性表是0个或者多个数据元素的有限序列,其中数据元素类型相同2.线性表可以逐项访问和顺序存储3.有顺序存储和链式存储两种存储方式。接下来,_c++线性表的顺序存储和链式存储https://jslhyh32.blog.csdn.net/article/details/131440870

一.理论精炼

        线性表没什么可说的,比较简单,大家姑且把他理解为数组即可。相较于顺序表的物理结构上也连续存取,链表在内存中的存储位置是离散的。在实现的过程中,多数参考资料愿意以带头节点的链表为例,如下图:

二.分配内存空间

先来看一下链表节点的定义方式: 

struct LNode{
	int data;
	LNode* next;
}; 

        初学者接触的时候有人会蒙圈——因为这相当于是嵌套定义,即类型里面又直接定义了一个指向自己类型的指针。但这恰恰是链表的“几何意义”:顺序表的定义就很符合人类的思维惯式,对吧,一个表,或者说是一个有顺序的集合一样,物理上就应该是连续的一堆东西连在一起——计算机的内存中实际上也是这么存放的,因此在定义的时候直接定义成和数组“长得一样”的类型。

        不过链表就不一样了,和他本身的逻辑意义一致——即各节点之间通过指针串起来,彼此之间是不连续的。因此在声明一个链表的时候,其实是声明了一个头结点——这样后面的元素根据指针就可以存在了!即声明的时候先声明一个,然后再根据指针域的值继续赋值。

1.malloc函数

malloc是用于申请分配动态内存的函数,这篇博客已经介绍过,这里不再赘述:

C语言malloc函数及数组初始长度的辨析-CSDN博客文章浏览阅读389次,点赞7次,收藏7次。知名的教材在编写中总是给出了很多伪代码,虽然说从意图上来说只要将代码的逻辑表达清楚就没什么问题,不过很多书中的伪码有些过于逆天,会误导许多基础不扎实的人;另一方面,毕竟每个人的编码习惯不同,可能有些高手喜欢写生僻的代码来让人云里雾里语法的规则。。。。https://jslhyh32.blog.csdn.net/article/details/140559079?spm=1001.2014.3001.5502如下,声明一个LNode类型的指针,再赋予空间:

	LNode* head;
	head=(LNode*)malloc(5*sizeof(LNode));

逻辑非常清晰明了,malloc返回的是地址,因此需要将这部分地址赋予一个指针~ 

2.new运算符

C++中,可以这样写:

LNode* p=new LNode;

没什么难度,这里主要想讲C,就不展开细说了。 

3.内存泄漏

C语言的设计者认为,程序员完全右能力自己控制内存的分配与释放,因此把对内存的控制、操作都分配给了程序员。使用完malloc等之后,一定要使用free将其释放:

free(head);

三.创建链表

先来直观的感受一下如何创建链表:

	LNode* node1=(LNode*)malloc(sizeof(LNode));
	LNode* node2=(LNode*)malloc(sizeof(LNode));
	LNode* node3=(LNode*)malloc(sizeof(LNode));
	
	node1->data=1;
	node1->next=node2;
	
	node2->data=2;
	node2->next=node3;
	
	node3->data=3;
	node3->next=NULL;

显然这样太死板了,没有人机交互,那么不妨我们改善一下,main函数中可以输入链表的长度,如下:

int main(int argc, char *argv[]) {
	
	printf("请输入链表的长度:");
	int num=0;
	scanf("%d",&num);
	
	LNode* List=createLinkList(num); //根据长度创建链表
	
	List=List->next; //第一个是头结点,因此从第二个开始才能遍历到数据
	while(List!=NULL)
	{
		printf("%d ",List->data);
		List=List->next;	
	} 
	

	return 0;
}

然后我们来编写createLinkList函数:

LNode* createLinkList(int x)
{
	LNode* head;// 声明头结点
	LNode* tNode;//当前结点
	LNode* pre;//当前结点的前驱节点
	head=(LNode*)malloc(sizeof(LNode));
	head->next=NULL;//初始化指针域为0 
	pre=head; 

	int i=1;
	for(;i<=x;i++)
	{
		tNode=(LNode*)malloc(sizeof(LNode));//创建一个新节点
		int temp=0;
		temp=i;
		tNode->data=temp;
		tNode->next=NULL;
		pre->next=tNode;
		pre=tNode; 
	} 
	return head;
	
}

(加前驱是为了方便链表的创建,也可以不这样做~)

 

如上图,没什么bug~


为了让大家直观感受一下所谓的【离散】,我们把链表中的节点地址也打印一下,修改main函数如下:

int main(int argc, char *argv[]) {
	
	printf("请输入链表的长度:");
	int num=0;
	scanf("%d",&num);
	
	LNode* List=createLinkList(num); //根据长度创建链表
	LNode* other=List; //另外单独存放一个头结点 
	printf("地址依次如下:\n");
	while(other!=NULL)
	{
		printf("%d ",&other);
		other=other->next;	
	} 
	printf("\n");
	printf("数值依次如下:\n");
	List=List->next; //第一个是头结点,因此从第二个开始才能遍历到数据
	while(List!=NULL)
	{
		printf("%d ",List->data);
		List=List->next;	
	} 

	return 0;
}

如下图:头结点和其他5个节点之间均不是连续的!

 

 另外,每次执行的地址也不尽相同。相信这样直观感受一下,各位就能理解到链表的物理意义了~

四.查找元素

查找就非常简单了,这里我们直接写一个统计某元素个数的函数,如下:

int SearchByValue(LNode* target,int x)
{
	int count=0;
	LNode* temp=target->next;
	while(temp!=NULL)
	{
		if(temp->data==x)
			count++;
		temp=temp->next;	
	} 
	return count;
}

main函数调用:

 

继续写别的~ 

五.插入元素

这个有点意思,因为需要交换两个指针,具体的逻辑这里不多说了,太基础了,这里放个图让大家看看,千万别被逻辑绕晕~

代码如下:

void InsertByPos(LNode* L,int pos,int x)
{
	LNode* temp=L;//将头结点的值赋给临时的节点
	int i=1;
	for(;i<=pos-1;i++) //找到待插入位置的前一个指针 
		temp=temp->next; 
	LNode* tNode;	
	tNode=(LNode*)malloc(sizeof(LNode)); //创建一个新节点
	tNode->next=temp->next;
	temp->next=tNode;
	
	tNode->data=x; 
}

main函数测试:

//3.测试 InsertByPos
	InsertByPos(List,4,32); 
	List=List->next; 
	while(List!=NULL)
	{
		printf("%d %d\n",List->data,&List->next);
		List=List->next;	
	} 

结果如下:

堪称完美~ 

六.删除元素

1.按值删除

简单,直接按照上面按值查询的代码写就好,只需要改变if条件的逻辑即可:

void DeleteByValue(LNode* L,int x)
{
	LNode* temp=L->next;//忽略头结点的第一个
	LNode* pre=L;//pre始终用来保存 
 	while(temp!=NULL)
	{
		if(temp->data==x)
			pre->next=temp->next;
		pre=temp;
		temp=temp->next;
			
	} 
}

main函数:

	
//4.测试DeleteByValue
	DeleteByValue(List,4);
	List=List->next; //第一个是头结点,因此从第二个开始才能遍历到数据
	while(List!=NULL)
	{
		printf("%d %d\n",List->data,&List->next);
		List=List->next;	
	} 

测试结果: 

4成功被删掉~

2.按位删除

根据插入元素的代码即可修改成功。题外话,其实这里还可以写一个按位查找,大家自己试试~

void DeleteByPos(LNode* L,int pos)
{
	LNode* temp=L->next;
	LNode* pre=L;
	int i=1;
	for(;i<=pos-1;i++) //找到待插入位置的前一个指针 
	{
		pre=temp;
		temp=temp->next; 	
	}
	pre->next=temp->next;	
	
} 

老套路:

	DeleteByPos(List,4);
	List=List->next; //第一个是头结点,因此从第二个开始才能遍历到数据
	while(List!=NULL)
	{
		printf("%d %d\n",List->data,&List->next);
		List=List->next;	
	} 
	free(List);
	return 0;

还是删除掉了第4位的元素~

主打一个过五关斩六将~ 

七.静态链表 

静态链表感觉没什么意思,感觉还不如直接用顺序表,大家自己看看就行,比较简单:

 


写在最后:无论408还是众多985名校的自命题,线性表都是算法题、大题考察的热门,大家一定要熟练掌握代码规范。至于二叉树乃至图论的具体编程实现,怎么说,要是你不是奔着140+去考,其实是可以允许自己不会的,参照二八定律——应该尽可能地从简易的20%里面获取占大头的80%分数。因此这期结束后也不优先更新各种数据结构的实现了,优先更新一些数学的问题,接着就是DFS、BFS、DP这些蓝桥杯等竞赛偏爱的内容。(说句题外话,蓝桥杯之所以被戏称圈钱杯、DP杯,就是因为近年来的考试题目逐渐以暴力和DP为主,在一个不是很发达的省份比如我们这里,即便是A组,如果你的DP异常熟练,拿个省一进国赛是没什么难度的。除了蓝桥杯还有CSP,如果代码基础非常扎实,会处理复杂的字符串,还能熟练掌握DP,考个300+似乎也不是很有难度。。由此可见DP的重要性!


完整的.c文件源码,有需要的自提:

链接:https://pan.baidu.com/s/1uN0elyL2N25vNhF2bSewoA 
提取码:hma8 

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

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

相关文章

谷粒商城实战笔记-56~57-商品服务-API-三级分类-修改-拖拽功能完成

文章目录 一&#xff0c;56-商品服务-API-三级分类-修改-拖拽功能完成二&#xff0c;57-商品服务-API-三级分类-修改-批量拖拽效果1&#xff0c;增加按钮2&#xff0c;多次拖拽一次保存完整代码 在构建商品服务API中的三级分类修改功能时&#xff0c;拖拽排序是一个直观且高效的…

Linux:Linux权限

目录 1. Linux权限的概念 2. Linux权限管理 2.1 文件访问者的分类 2.2 文件类型和访问权限 2.2.1 文件类型 2.2.2 基本权限 2.3 文件权限值的表示方法 2.4 文件访问权限的相关设置方法 2.4.1 chmod 2.4.2 chown 2.4.3 chgrp 2.4.4 umask 3. file指令 4. Linux目…

如何学习EMR:糙快猛的大数据之路(建立整体框架)

目录 初学EMREMR是什么&#xff1f;我的EMR学习故事糙快猛学习法则代码示例: 你的第一个EMR任务学习EMR的深入步骤EMR进阶技巧实用资源推荐常见挑战和解决方案 EMR生态EMR生态系统深度探索1. EMR上的Hadoop生态系统2. EMR Studio3. EMR on EKS 高级EMR配置和优化1. EMR实例集策…

音视频入门基础:PCM专题(3)——使用Audacity工具分析PCM音频文件

音视频入门基础&#xff1a;PCM专题系列文章&#xff1a; 音视频入门基础&#xff1a;PCM专题&#xff08;1&#xff09;——使用FFmpeg命令生成PCM音频文件并播放 音视频入门基础&#xff1a;PCM专题&#xff08;2&#xff09;——使用Qt播放PCM音频文件 音视频入门基础&am…

ICML 2024最佳论文开奖了!今年的热门投稿方向有这些

ICML 2024最近也放榜啦&#xff01;今年共有10篇论文夺得最佳论文奖&#xff0c;包括火爆的Stable Diffusion 3、谷歌VideoPoet以及世界模型Genie。 ICML是国际机器学习顶会&#xff0c;也是CCF-A类学术会议。今年这届顶会一共收到了9473篇论文&#xff0c;其中2610篇被录用&am…

昇思25天学习打卡营第22天|基于MindNLP+MusicGen生成自己的个性化音乐

文章目录 昇思MindSpore应用实践1、MusicGen模型简介残差矢量量化&#xff08;RVQ&#xff09;SoundStreamEncodec 2、生成音乐无提示生成文本提示生成音频提示生成 Reference 昇思MindSpore应用实践 本系列文章主要用于记录昇思25天学习打卡营的学习心得。 1、MusicGen模型简…

Qt基础 | Qt SQL模块介绍 | Qt SQL模块常用类及其常用函数介绍

文章目录 一、Qt SQL模块概述1.Qt sql 支持的数据库2.SQLite 数据库3.Qt SQL 模块的主要类 一、Qt SQL模块概述 Qt SQL 模块提供数据库编程的支持&#xff0c;Qt 支持多种常见的数据库&#xff0c;如MySQL、Oracle、MS SQL Server、SQLite 等。Qt SQL 模块包括多个类&#xff0…

phpstorm配置xdebug3

查看php路径相关信息 php --ini安装xdebug https://www.jetbrains.com/help/phpstorm/2024.1/configuring-xdebug.html?php.debugging.xdebug.configure php.ini 配置 在最后添加&#xff0c;以下是我的配置 [xdebug] zend_extension/opt/homebrew/Cellar/php8.1/8.1.29/p…

安装NVIDIA驱动

一、不升级内核安装NVIDIA驱动 说明: 1、安装NVIDIA驱动,是用来提升AI、图片等算法 2、本人是在centos7.9操作系统安装英伟达T4板卡驱动 操作系统Centos 7.9驱动版本NVIDIA-Linux-x86_64-525.89.02.run操作账号root1.1 关闭nouveau 1、查看nouveau是否关闭 lsmod |grep nouv…

Android 常用调试工具/方法解析

一、内存相关 参考Android内存分析命令_dumpsys meminfo 算出rss-CSDN博客 1、基本概念 1&#xff09;PSS & RSS & USS & VSS a、PSS 概念&#xff1a;全称Proportional Set Size&#xff0c;根据进程实际使用的内存量按照共享比例分配给进程的一种内存度量方…

MySql性能调优05-[sql实战演练]

sql实战演练 行列转换行列式转换第一题【列转行】第二题【列转行】 having的使用找到表中&#xff0c;名字重复的项有数据表employee&#xff0c;包含如下字段id、name、department、age&#xff0c;编写SQL&#xff0c;找到不与其他人同龄的年纪最大的员工的年龄有数据表emplo…

Nacos-2.4.0最新版本docker镜像,本人亲自制作,部署十分方便,兼容postgresql最新版本17和16,奉献给大家了

基于Postgresql数据库存储的nacos最新版本2.4.0,采用docker镜像安装方式 因业务需要,为了让nacos支持postgresql,特意花了两天时间修改了源码,然后制作了docker镜像,如果你也在找支持postgresql的nacos最新版本,恭喜你,你来的正好~ nacos-2.4.0 postgresql的数据库脚本…

C++学习笔记-C++11中的智能指针

1.智能指针介绍 智能指针是C的特性用法&#xff0c;是一个类似指针功能的类对象&#xff0c;其目的是为了更好的管理动态分配的内存&#xff0c;避免出现内存泄漏、悬空指针等问题。C11的标准库里提供了三种智能指针模板类&#xff0c;分别是std::unique_ptr、std::shared_ptr…

vue 两个页面切换, 再回到当前页,还是离开前的数据

1、要保证页面的name 和 建路由的大小写一致 2、页面不用生命周期--activated 调接口刷新

计算机网络八股文(三)

目录 41.为什么每次建立TCP连接时&#xff0c;初始化的序列号都不一样&#xff1f; 42.初始序列号ISN如何随机产生&#xff1f; 43.既然IP层会分片&#xff0c;为什么TCP层需要根据MSS分片呢&#xff1f; 44.TCP第一次握手丢失&#xff0c;会发生什么&#xff1f; 45.TCP第…

一个python脚本解决新版剪映导出字幕收费问题

如果你是希望我能完全解决剪映收费问题&#xff0c;我无法帮你&#xff1b; 两个文件&#xff0c;可生成不带时间线的纯文案&#xff0c;MD 格式&#xff0c;也可以生成带时间线的 SRT 文件。 因为剪映国内版对 JSON 文件进行了加密&#xff0c;所以请选择国际版 Cutcap&#x…

《javaEE篇》--阻塞队列详解

阻塞队列 阻塞队列概述 阻塞队列也是一种队列&#xff0c;和普通队列一样遵循先进先出的原则&#xff0c;但是阻塞队列相较于普通队列多了两项功能阻塞添加和阻塞移除&#xff0c;使得阻塞队列成为一种线程安全的数据结构 阻塞添加&#xff1a;当队列满的时候继续入队就会阻…

电脑虚拟摄像头软件分享|用手机打破电脑摄像头的极限

随着手机摄像头的不断更新迭代&#xff0c;手机已经接近专业电脑摄像头的画质。这让我们可以花费更低的成本获取优质的电脑录像画面。今天小编给大家详细讲解电脑虚拟摄像头的在我们日常生活中的妙用&#xff0c;以及分享几款口碑不错的电脑虚拟摄像头软件。有需要的小伙伴可以…

从业务到数据,大模型应用成功的再思考!

自2022年底OpenAI发布ChatGPT以来&#xff0c;大模型在企业的应用方兴未艾。 大模型必须要结合落地应用&#xff0c;才算是长出手跟脚&#xff0c;真正应用于实际业务场景的解决方案中&#xff0c;配合“大脑”完成任务。从医疗诊断到自动驾驶&#xff0c;从个性化营销到智能客…

数据结构重置版(概念篇)

本篇文章是对数据结构的重置&#xff0c;且只涉及概念 顺序表与链表的区别 不同点 顺序表 链表 存储空间上 物理上一定连续 逻辑上连续&#xff0c;但物理上不一定连续…