【数据结构篇】~单链表(附源码)

news2024/9/22 1:58:18

【数据结构篇】~链表

  • 链表前言
  • 链表的实现
    • 1.头文件
    • 2.源文件

链表前言

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
1、链式机构在逻辑上是连续的,在物理结构上不一定连续​
2、结点一般是从堆上申请的​
3、从堆上申请来的空间,是按照一定策略分配出来的,每次申请的空间可能连续,可能不连续​当我们想要保存一个整型数据时,实际是向操作系统申请了一块内存,这个内存不仅要保存整型数据,也需要保存下一个结点的地址(当下一个结点为空时保存的地址为空)。
当我们想要从第一个结点走到最后一个结点时,只需要在当前结点拿上下一个结点的地址就可以了。

如图:在这里插入图片描述
既然链表是有一个个节点组成的那我们就可以把它看成一个小火车!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

链表的实现

1.头文件

#pragma once
#include <stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int sldatatype;//因为不知道要保存什么类型的数据
//定义节点的结构体
typedef struct slistnode {
	sldatatype data;//保存的数据
	struct slistnode* next;//指向下一个结构体的指针
}slnode;
void slprint(slnode* phead);
//打印链表(这里要传链表头的地址,以确保能找到链表)
//phead的作用就和火车头差不多
slnode* slbuynode(sldatatype);//申请新节点
void slpushback(slnode** pphead, sldatatype x);
//尾插(因为要通过函数改变数据所以就要传‘址’调用,不能‘传值’)
//所以这里是‘二级’指针!
void slpushfornt(slnode** pphead, sldatatype x);//头插
void slpopback(slnode** pphead);//尾删
void slpopfornt(slnode** pphead);//头删
//查找
slnode* slfind(slnode* phead, sldatatype x);
//在指定位置之前插入数据
void slinsert(slnode** pphead, slnode* pos, sldatatype x);
//删除pos结点
void slerase(slnode** pphead, slnode* pos);
//在指定位置之后插入数据
void slinsertAfter(slnode* pos, sldatatype x);
//删除pos之后的结点
void sleraseAfter(slnode* pos);
//销毁链表
void sldestroy(slnode** pphead);

2.源文件

#include"slist.h"
//断言pphead的目的是不能对空地址进行解引用!
void slprint(slnode* phead)//打印链表
{
	slnode* pcur = phead;
	while(pcur)
	{
		printf("%d->", pcur->data);//打印数据
		pcur = pcur->next;//改变purc的指向,让它指向下一个节点
	}
	printf("NULL\n");
}
slnode* slbuynode(sldatatype x)//申请新节点
{
	slnode* newnode = (slnode*)malloc(sizeof(slnode));
	//一开辟空间就要检查是否开辟成功
	if (newnode==NULL)
	{
		perror("malloc fail");
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
void slpushback(slnode** pphead,sldatatype x)//尾插(pphead==&plist)
{     
	slnode* pcur = *pphead;

	//既然要插入数据那么就要开辟新空间(新节点)
	slnode* newnode = slbuynode(x);
	assert(pphead);
	if (*pphead==NULL)//如果是空链表(plist==null)
	{
		*pphead = newnode;
		newnode->data = x;
	}
	else//不是空链表
	{		
		while (pcur->next)
		{
			pcur = pcur->next;
		}
		newnode->data = x;
		pcur->next = newnode;		
	}	
}
void slpushfornt(slnode** pphead, sldatatype x)//头插
{
	
	//既然要插入数据那么就要开辟新空间(新节点)
	slnode* newnode = slbuynode(x);
	assert(pphead);
		newnode->next = *pphead;//为了把新结点和原来的链表连起来
		*pphead = newnode;	
}
void slpopback(slnode** pphead)//尾删
{
	//删除时,pphead(不能对null进行解引用)和头节点(不然没意义了)都不能为空
	assert(pphead&&*pphead);
	
	if ((*pphead)->next==NULL)//只有一个节点
	{
		free(*pphead);
		(*pphead)->next = NULL;
	}
	else
 {         slnode* ptail = *pphead;
	      slnode* prev = NULL;
		while (ptail->next)//跳出循环时ptail就是最后一个节点
		{	
			prev = ptail;
			ptail = ptail->next;
		}
		prev->next = NULL;
		free(ptail);
		ptail = NULL;
	}
}
void slpopfornt(slnode**pphead)//头删
{
	//删除时,pphead(不能对null进行解引用)和头节点(不然没意义了)都不能为空
	assert(pphead && *pphead);
	slnode* node = (*pphead)->next;//(->)的优先级大于(*(解引用))所以要用()
	free(*pphead);
	*pphead = NULL;
	*pphead = node;	
}
//查找
//因为查找数据不需要改变链表内容所以这里传一级指针
slnode* slfind(slnode* phead, sldatatype x)
{
	assert(phead);//不能在空链表中查找数据
	slnode* node = phead;
	while (node)
	{
		if (x == node->data)
		{
			return node;
		}
		node = node->next;
	}
	return NULL;
}
//在指定位置之前插入数据(要改变的指针有pos的前驱节点和pos)
void slinsert(slnode** pphead, slnode* pos, sldatatype x)
{
	assert(pphead);
	assert(pos);
	slnode* newnode = slbuynode(x);
	if (pos == *pphead)//pos是头节点就调用’头插‘
	{
		slpushfornt(pphead,x);
	}
	else//pos不是头节点
	{	
		slnode* prev = *pphead;//定义pos的前一个节点以便连接
		while (prev->next!=pos)
		{
			prev = prev->next;
		}
		//出循环就代表pos的前驱节点已找到!
		newnode->next = pos;
		prev->next = newnode;
	}
}
//在指定位置之后插入数据
//在pos后插入数据要改变的指针有(pos、pos->next)
void slinsertAfter(slnode* pos, sldatatype x)
{
	assert(pos);
	slnode* newnode = slbuynode(x);
	slnode* next = pos->next;
	newnode->next = pos->next;
	pos->next = newnode;	
}
//删除pos结点
//删除pos后改变的指针有(pos的前驱节点和pos的next指针)
void slerase(slnode** pphead, slnode* pos)
{
	assert(pphead && pos);//不能删除空节点
	if (pos == *pphead)//如果pos是头节点就进行头删
	{	
		slpopfornt(pphead);
	}
	else//不是头节点
	{
		slnode* prev = *pphead;
		slnode* next = pos->next;
		while(prev->next!=pos)
		{
			prev = prev->next;
		}
		//出循环后找到了pos的前驱节点
		prev->next = next;
		free(pos);
		pos = NULL;
	}

}

//删除pos之后的结点
//删除pos之后的结点要改变的指针有(pos和pos->next)
void sleraseAfter(slnode* pos)
{
	assert(pos);
	slnode* del = pos->next;
	pos->next = pos->next->next;
	free(del);
	del = NULL;
}
//销毁链表
void sldestroy(slnode** pphead)
{
	assert(pphead&&*pphead);//不能销毁空链表
	slnode* purc = *pphead;
	while (purc)
	{
		slnode* next =purc->next ;
		free(purc);
		purc = next;	
	}
	//头节点还没销毁
	*pphead = NULL;
}

详解都在注释中哦!

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

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

相关文章

Java二十三种设计模式-命令模式(18/23)

命令模式&#xff1a;将请求封装为对象的策略 概要 本文全面探讨了命令模式&#xff0c;从基础概念到实现细节&#xff0c;再到使用场景、优缺点分析&#xff0c;以及与其他设计模式的比较&#xff0c;并提供了最佳实践和替代方案&#xff0c;旨在帮助读者深入理解命令模式并…

【xr-frame】微信小程序xr-frame典型案例

微信小程序xr-frame典型案例 在之前的工作中&#xff0c;我大量使用XR-Frame框架进行AR开发&#xff0c;并积累了一些案例和业务代码。其中包括2D图像识别、手部动作识别、Gltf模型加载、动态模型加载、模型动画等内容。小程序部分使用TypeScript编写&#xff0c;而XR-Frame组…

利用puppeteer将html网页生成图片

1.什么是puppeteer&#xff1f; Puppeteer是一个Node库&#xff0c;它提供了一个高级API来通过DevTools协议控制Chromium或Chrome。 可以使用Puppeteer来自动化完成浏览器的操作&#xff0c;官方给出的一些使用场景如下&#xff1a; 生成页面PDF抓取 SPA&#xff08;单页应用…

3.Windows Login Unlocker-忘记电脑密码也可以解决

想要解锁Windows系统的开机密码&#xff0c;但官网的传统方法只适合Windows本地账户&#xff0c;对微软账户或PIN码()束手无策&#xff1f;别担心&#xff0c;小编之前推荐过的「Windows Login Unlocker」软件能为您排忧解难。这款出色的工具不仅能够轻松绕过各种Windows密码&a…

C语言-写一个用矩形法求定积分的通用函数,分别求积分区间为[0,1]sinx,cosx,e的x方的定积分

一、题目要求&#xff1a; 二、思路 ①数学方面:矩形法求定积分的公式 将积分图形划分成为指定数量的矩形&#xff0c;求取各个矩形的面积&#xff0c;然后最终进行累加得到结果 1.积分区间: [num1, num2] 2.分割数量:count 每个矩形的边长:dx(num2-num1)/count 3.被积分…

智慧草莓基地管理系统--论文pf

TOC springboot359智慧草莓基地管理系统--论文pf 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xf…

泰安鲁菜根普照店重装开业:传承与创新并举 品味舌尖上的泰安

8月17日&#xff0c;泰安鲁菜根普照店重装开业。店内装修以泰山文化为主题&#xff0c;营造出一种浓郁的地方文化特色氛围。这家以泰山文化为底蕴&#xff0c;以大汶河传统民俗食材为基础的餐饮企业&#xff0c;一直致力于发掘和传承泰山周边及汶河两岸的传统特色美食&#xff…

【漫谈C语言和嵌入式009】探索LVDT:线性可变差动变压器的工作原理与应用

引言 在现代工业和工程领域中&#xff0c;精确的位移测量是许多系统正常运行的关键。线性可变差动变压器&#xff08;LVDT, Linear Variable Differential Transformer&#xff09;是一种广泛使用的位移传感器&#xff0c;因其高精度、可靠性和耐用性在各种应用中得到了普遍认可…

iOS(OC)学习第1天-怎么设置UI

xCode 版本为 新建工程 xCode->iOS->App->输入工程名称 项目结构 storyboard文件&#xff1a;可以通过拖动方式添加UI的UI布局文件&#xff0c;理解为Android的XML布局文件 名字说明Main.storyboard首页LaunchScreen.storyboard引导页 添加布局 引导页 设置组件的属…

复现DOM破坏案例

准备工作&#xff1a; 做好代理然后访问靶场 XSS Game - Learning XSS Made Simple! | Created by PwnFunction 第一关 Ma Spaghet! 这是源代码部分&#xff1a; <!-- Challenge --> <h2 id"spaghet"></h2> <script> spaghet.innerHTM…

【推荐100个unity插件之25】使用Vroid进行二次元建模,并在unity中使用VRM模型——URP-UniVrm插件的使用

最终效果 文章目录 最终效果什么是Vriod官网地址下载安装使用导出模型unity使用VRM模型导入URP-UniVrm插件 Blender使用Blender安装Cats Blender Plugin 插件Blender安装VRM-Addon-for-Blender插件导入VRM模型导出为FBX模型 使用别人的VRM模型完结 什么是Vriod 如果你玩过能捏…

经典动作手机游戏:《艾希》安卓手机游戏下载

《艾希手游》是一款以女性为主角的游戏&#xff0c;玩家在游戏中将扮演主角艾希&#xff0c;在各种场景中进行冒险&#xff0c;探索剧情和解开谜题。这款游戏的画面精美&#xff0c;操作简单易上手&#xff0c;同时提供了丰富的剧情和多样的玩法。 下载地址&#xff1a;https:/…

氙灯老化试验箱试验机

氙灯老化试验箱&#xff0c;采用6.5KW大功率的精密水冷式氙灯&#xff0c;曝晒面积达到了6500cm2 功能强大&#xff0c;测试结果可靠 ◆ 满足国内外所有氙灯测试标准要求。 ◆ 采用氙灯灯管及滤光器组件&#xff0c;保证试验数据的可比性和重现性。 ◆ 自动旋转式三层鼓型样板架…

MATLAB根据数值画直方图

一直很纠结MATLAB为什么不提供根据数值&#xff08;或统计值&#xff09;画直方图的函数&#xff0c;只给一个不专业的bar&#xff0c;原来histogram支持。 edges [0-0.5:70.5]; counts [508 821 898 892 552 181 159 85];figure; histogram(BinEdges,edges,BinCounts,count…

SAP Memory ABAP Memory超级详细解析

SAP Memory & ABAP Memory超级详细解析_abap set parameter id-CSDN博客 FREE MEMORY ID ZTESTMAT. 清空指定的ABAPmemory FREE MEMORY. 清空externalsession内的所有ABAPmemory 最后请注意 IMPORT…

【Spring Boot-SpringBoot怎么实现自动配置】

目录 什么是Spring Boot自动配置 自动配置中需要的重要注解 一.Condition 二.Enable 三.EnableAutoConfiguration 实现一个自定义starter 什么是Spring Boot自动配置 SpringBoot的自动配置简单来说就是当spring容器启动后&#xff0c;一些配置类、bean对象就自动存入到了…

Python新手入门指南:从零开始学编程

欢迎来到Python的世界&#xff01;Python是一种功能强大、易于学习且用途广泛的编程语言。无论你是完全没有编程经验的新手&#xff0c;还是想要学习新技能的开发者&#xff0c;Python都是一个非常好的起点。接下来&#xff0c;我们将一起踏上这段编程之旅&#xff0c;从基础语…

机器学习第十一章-特征选择与稀疏学习

11.1子集收集与评价 属性称为"特征" &#xff0c;对当前学习任务有用的属性称为"相关特征" 、没什么用的属性称为"无关特 征" . 从给定的特征集合中选择出相关特征于集的过程&#xff0c;称为"特征选择"。 特征选择是一个重要的"…

Linux系统中的弹性计算功能

在当今数字化时代&#xff0c;弹性计算已经成为信息技术领域的重要概念之一。弹性计算指的是根据需要自动调整计算资源&#xff0c;以满足应用程序的需求。这种灵活性和自适应性使得弹性计算成为了云计算、大数据、人工智能等领域的核心技术之一。在这个领域中&#xff0c;Linu…

嵌入式软件--数电基础 DAY 4

1.SR锁存器 1》四种状态&#xff1a; S R Q Q set状态&#xff1a; 0 1 1 0 Reset状态&#xff1a; 1 0 0 1 维持状态&#xff1a; 1 1 维持上个状态 无意义状态…