单链表的应用(附代码)

news2024/9/20 14:29:24

链表

链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。其实链表可以想象为小火车,链表比顺序表具有更好的灵活性,只需要通过指针的改变就可以实现增删查改。

这是逻辑思维下链表的样子

代码构造:

struct SListNode
{
int data; //结点数据
struct SListNode* next; //指针变量⽤保存下⼀个结点的地址
};

节点

与顺序表不同的是,链表⾥的每节"⻋厢"都是独⽴申请下来的空间,我们称之为“结点/结点”结点的组成主要有两个部分:当前结点要保存的数据和保存下⼀个结点的地址(指针变量)。链表中每个结点都是独⽴申请的(即需要插⼊数据时才去申请⼀块结点的空间),我们需要通过指针变量来保存下⼀个结点位置才能从当前结点找到下⼀个结点。

具体分析

实现链表功能的几个步骤:申请新的节点,头插或者尾插,头删尾删,找到指定的节点,插入到指定位置的前一个或者后一个,最后销毁链表。

此处我们代码中会出现形参实参的传地址的调用,为了便于理解特意附了一个图片进行理解

传址调用实参形参示意图

 

申请节点:

slist* slistnewnode(typedata x)
{
	slist* node = (slist*)malloc(sizeof(slist));
	if (node == NULL)
	{
		perror("fail!!!");
		exit(1);
	}
	node->data = x;
	node->next = NULL;
	return node;
}

头插尾插:

//头插
void slistfrondpush(slist** s1, typedata x)
{
	//sl不能为空如果为空*s1无法解引用
	assert(s1);
	slist *newnode=slistnewnode(x);
	newnode->next = *s1;
	*s1 = newnode;
}
//尾插
void slistbackpush(slist** s1, typedata x)
{
	//尾插要考虑是这个链表是否为空
	//不为空要找到末尾元素
	assert(s1);
	slist* newnode = slistnewnode(x);
	if (*s1 == NULL)
	{
		*s1 = newnode;
	}
	else
	{
		slist* pcur = *s1;
		while (pcur->next)
		{
			pcur = pcur->next;
		}
		pcur->next = newnode;
	}
}
头插示意图
尾插示意图

 尾插:要注意一点传入时,节点为空那就是尾插,不为空时寻找尾节点就行,然后进行插入。

头删尾删:

//尾删除
void slistbackpop(slist** sl)
{
	assert(sl && *sl);
	//当只有一个节点时的情况,第二种就是找到末尾的前一个位置
	slist* pcur=NULL;
	slist* next = *sl;
	if ((*sl)->next == NULL)
	{
		free(*sl);
		*sl = NULL;
	}
	else
	{
		while (next->next)
		{
			pcur = next;
			next = next->next;
		}
		pcur->next = NULL;
		free(next);
		next = NULL;
	}
}

 

找到指定的节点:

slist* slistfind(slist* sl, typedata x)
{
	assert(sl);
	slist* pcur = sl;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

 指定位置之前,之后插入

//在指定位置之前插入
void slistInter(slist** s1, slist* pos, typedata x)
{
	assert(s1);
	assert(pos);
	//当只有一个节点的时候此时在指定位置之前插入其实就是头插
	if (*s1 == pos)
	{
		slistfrondpush(s1, x);
	}
	else
	{
		slist* newnode = slistnewnode(x);
		slist* prev = *s1;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		newnode->next = pos;
		prev->next = newnode;

	}
	
}
//指定位置后插入元素
void slistInterafter(slist* pos, typedata x)
{
	assert(pos);
		slist* newnode = slistnewnode(x);
		newnode->next = pos->next;
		pos->next = newnode;
}

 

 删除pos后的节点

void slistEraseAfter(slist * pos)
{
		assert(pos && pos->next);
		slist* del = pos->next;
		pos->next = pos->next->next;
		free(del);
		del = NULL;
}

 

销毁链表:

void slistDestory(slist** s1)
{
	assert(s1 && *s1);
	slist* pcur = *s1;
	while (pcur)
	{
		slist* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*s1 = NULL;
}

代码展示

slist.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int typedata;
typedef struct slist
{
	typedata data;
	struct slist* next;
}slist;

//链表打印
void slistPrint(slist*sl);
//此处传参是用的二级指针;传值调用形参的改变不会影响实参
// s1-->&s
// *s1-->s
//链表的销毁
void slistDestory(slist** s1);
//节点的申请
slist * slistnewnode(typedata x);
//插入,尾插头插
void slistfrondpush(slist** s1, typedata x);
void slistbackpush(slist** s1, typedata x);
//删除,头删尾删
void slistfrondpop(slist** sl);
void slistbackdpop(slist** sl);
//查找元素
slist* slistfind(slist* sl, typedata x);
//指定位置前插入元素
void slistInter(slist** s1, slist* pos, typedata x);
//指定位置后插入元素
void slistInterafter(slist** s1, slist* pos, typedata x);
//删除pos节点
void slistErase(slist** sl, slist* pos);
//删除pos之后的节点
//void slistEraseAfter( slist* pos);

slist.c

#include"Slist.h"
void slistPrint(slist* sl)
{
	slist* pcur = sl;
	while (pcur)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}
//
void slistDestory(slist** s1)
{
	assert(s1 && *s1);
	slist* pcur = *s1;
	while (pcur)
	{
		slist* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*s1 = NULL;
}
//实现插入的时候首先要申请一个节点
slist* slistnewnode(typedata x)
{
	slist* node = (slist*)malloc(sizeof(slist));
	if (node == NULL)
	{
		perror("fail!!!");
		exit(1);
	}
	node->data = x;
	node->next = NULL;
	return node;
}
void slistfrondpush(slist** s1, typedata x)
{
	//sl不能为空如果为空*s1无法解引用
	assert(s1);
	slist *newnode=slistnewnode(x);
	newnode->next = *s1;
	*s1 = newnode;
}
void slistbackpush(slist** s1, typedata x)
{
	//尾插要考虑是这个链表是否为空
	//不为空要找到末尾元素
	assert(s1);
	slist* newnode = slistnewnode(x);
	if (*s1 == NULL)
	{
		*s1 = newnode;
		
	}
	else
	{
		slist* pcur = *s1;
		while (pcur->next)
		{
			pcur = pcur->next;
		}
		pcur->next = newnode;
	}
}
//头删,要考虑只有一个节点是的情况
void slistfrondpop(slist** sl)
{
	//头删要保证不能是一个空链表
	assert(sl && *sl);
	slist* next = (*sl)->next;
	free(*sl);
	*sl = next;
}
//尾删除
void slistbackpop(slist** sl)
{
	assert(sl && *sl);
	//当只有一个节点时的情况,第二种就是找到末尾的前一个位置
	slist* pcur=NULL;
	slist* next = *sl;
	if ((*sl)->next == NULL)
	{
		free(*sl);
		*sl = NULL;

	}
	else
	{
		while (next->next)
		{
			pcur = next;
			next = next->next;
		}
		pcur->next = NULL;
		free(next);
		next = NULL;
	}
}
//查找元素
slist* slistfind(slist* sl, typedata x)
{
	assert(sl);
	slist* pcur = sl;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}
//在指定位置之前插入
void slistInter(slist** s1, slist* pos, typedata x)
{
	assert(s1);
	assert(pos);
	
	//当只有一个节点的时候此时在指定位置之前插入其实就是头插
	if (*s1 == pos)
	{
		slistfrondpush(s1, x);
	}
	else
	{
		slist* newnode = slistnewnode(x);
		slist* prev = *s1;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		newnode->next = pos;
		prev->next = newnode;

	}
	
}
//指定位置后插入元素
void slistInterafter(slist** s1, slist* pos, typedata x)
{
	assert(s1);
	assert(pos);

	//当只有一个节点的时候此时在指定位置之前插入其实就是头插
	if (*s1 == pos)
	{
		slistbackpush(s1, x);
	}
	else
	{
		slist* newnode = slistnewnode(x);
		slist* prev = *s1;
		while (prev!= pos)
		{
			prev = prev->next;
		}
		newnode->next = pos->next;
		prev->next = newnode;
	}
}
//删除pos节点
void slistErase(slist** sl, slist* pos)
{
	assert(sl && *sl);
	assert(pos);
	
	if (pos == *sl)
	{
		slistfrondpop(sl);
	}
	else 
	{
		slist* prev = *sl;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
//删除pos之后的节点
void slistEraseAfter(slist * pos)
{
		assert(pos && pos->next);
		slist* dl = pos->next;
		pos->next = pos->next->next;
		free(dl);
		dl = NULL;
}

test.c

#include"Slist.h"
void test01()
{
	slist *s=NULL;
	//*s第一个节点
	//s指向第一个节点的指针
	//&s指向第一个节点的指针的地址
	slistfrondpush(&s, 1);
	slistbackpush(&s, 2);
	slistbackpush(&s, 3);
	slistbackpush(&s, 4);
	slistbackpush(&s, 5);
	slistfrondpop(&s);
	
	slistbackpop(&s);
	
	
	slist *find=slistfind(s, 4);
	if (find == NULL)
	{
		printf("未找到!\n");
	}
	else
	{
		printf("找到了!\n");
	}
	slistInter(&s, find, 6);
	slistInterafter(&s, find, 6);
	slistPrint(s);
	slistErase(&s, find);
	//删除pos之后的节点
	slistEraseAfter(find);
	slistPrint(s);
	slistDestory(&s);
	
}
int main()
{
	test01();
	return 0;
}

总结

以上就是单链表所实现的功能,如有不全期待各位大佬的积极指正,最后期待各位大佬能留下一个三连支持博主一下。

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

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

相关文章

使用TensorRT对YOLOv8模型进行加速推理

这里使用GitHub上shouxieai的 infer框架 对YOLOv8模型进行加速推理&#xff0c;操作过程如下所示&#xff1a; 1.配置环境&#xff0c;依赖项&#xff0c;包括&#xff1a; (1).CUDA: 11.8 (2).cuDNN: 8.7.0 (3).TensorRT: 8.5.3.1 (4).ONNX: 1.16.0 (5).OpenCV: 4.10.0 2.clon…

redis:Linux安装redis,redis常用的数据类型及相关命令

1. 什么是NoSQL nosql[not only sql]不仅仅是sql。所有非关系型数据库的统称。除去关系型数据库之外的都是非关系数据库。 1.1为什么使用NoSQL ​ NoSQL数据库相较于传统关系型数据库具有灵活性、可扩展性和高性能等优势&#xff0c;适合处理非结构化和半结构化数据&#xff0c…

服务运营|摘要:INFORMS 近期收益管理(Revenue Management )相关文章

编者按&#xff1a; 本期涵盖了INFORMS与收益管理相关的文章及其基本信息。 Title: Online Learning for Constrained Assortment Optimization Under Markov Chain Choice Model 基于马尔可夫链选择模型的约束下选品优化的在线学习 Link: https://pubsonline.informs.org/do…

召唤生命,阻止轻生——《生命门外》

本书的目的&#xff0c;就是阻止自杀&#xff01;拉回那些深陷在这样的思维当中正在挣扎犹豫的人&#xff0c;提醒他们珍爱生命&#xff0c;让更多的人&#xff0c;尤其是年轻人从执迷不悟的犹豫徘徊中幡然醒悟&#xff0c;回归正常的生活。 网络上抱孩子跳桥轻生的母亲&#…

Linux中gdb调试器的使用

Linux调试器&#xff1a;gdb gdb简介基本使用和常见的指令断点相关运行相关命令 gdb简介 我们都知道一个程序一般有两个版本分别是debug&#xff0c;和release版本&#xff0c;后者就是发布给用户的版本&#xff0c;而前者就是我们程序员用来调试用的版本。 他们有什么区别呢&…

Docker搭建Mysql主从复制,最新,最详细

Docker搭建Mysql主从复制&#xff0c;最新&#xff0c;最详细 这次搭建Mysql主从复制的时候&#xff0c;遇到不少问题&#xff0c;所以本次重新记录一下&#xff0c;使用Docker搭建一主三从的Mysql 一、Docker-Compose创建4个Mysql容器 1.1 创建对应的映射文件夹和对应的配置…

GitLab的安装步骤与代码拉取上传操作

一、GitLab的安装 详情见如下博客链接&#xff1a;gitlab安装 二、GitLab配置ssh key &#xff08;1&#xff09;打开Git Bash终端生成SSH和添加步骤 1、全局配置git用户名 git config --global user.name "xxx"注意&#xff1a;xxx为你自己gitlab的名字 2、全局…

JavaScript递归菜单栏

HTML就一个div大框架 <div class"treemenu"></div> 重中之重的JavaScript部分他来啦&#xff01; 注释也很清楚哟家人们&#xff01; let data; let arr []; let cons;let xhr new XMLHttpRequest(); // 设置请求方式和请求地址 xhr.open(get, ./js…

Linux上如何分析进程内存分配,优化进程内存占用大小

云计算场景下,服务器上内存宝贵,只有尽可能让服务器上服务进程占用更少的内存,方才可以提供更多的内存给虚拟机,卖给云客户。 虚拟化三大件:libvirt、qemu、kvm内存开销不小,可以优化占用更少的内存。如何找到进程内存开销的地方直观重要,以qemu为例说明。 一、查看进…

别让不专业的HR逼走你的人才!人力资源管理应该遵循哪些原则?

优秀的HR能够带领整个人力资源部门为企业招揽人才、培养人才和留住人才&#xff0c;促使人才为企业的业务增长提供支持。而不专业的HR&#xff0c;不仅无法做到这些&#xff0c;还会把企业原有的人才逼走&#xff0c;因为不合适的人力管理也是导致人才离职的原因。所以&#xf…

【C++】前缀和算法专题

目录 介绍 【模版】一维前缀和 算法思路&#xff1a; 代码实现 【模版】二维前缀和 算法思路 代码实现 寻找数组中心的下标 算法思路 代码实现 总结 除自身以外数组的乘积 算法思路 代码实现 和为K的子数组 算法思路 代码实现 和可被整除的K的子数组 算法思…

C++ 操作Git仓库

代码 #include "common.h" #include "args.c" #include "common.c"enum index_mode {INDEX_NONE,INDEX_ADD };struct index_options {int dry_run;int verbose;git_repository* repo;enum index_mode mode;int add_update; };/* Forward declar…

Python零基础详细入门教程

Python零基础详细入门教程可以从以下几个方面展开&#xff0c;帮助初学者系统地学习Python编程&#xff1a; 一、Python基础入门 1. Python简介 Python的由来与发展&#xff1a;Python是一种广泛使用的高级编程语言&#xff0c;以其简洁的语法和强大的功能而受到开发者的喜爱…

2024第二十届中国国际粮油产品及设备技术展示交易会

2024第二十届中国国际粮油产品及设备技术展示交易会 时间&#xff1a;2024年11月15-17日 地点&#xff1a; 南昌绿地国际博览中心 展会介绍&#xff1a; 随着国家逐年加大对农业的投入&#xff0c;调整农业产业结构&#xff0c;提高农产品附加值&#xff0c;促进农民增收。…

CRMEB-众邦科技 使用笔记

1.启动项目报错 Unable to load authentication plugin ‘caching_sha2_password’. 参考&#xff1a;http://t.csdnimg.cn/5EqaE 解决办法&#xff1a;升级mysql驱动 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</ar…

超级弱口令检查工具

一、背景 弱口令问题主要源于用户和管理员的安全意识不足&#xff0c;以及为了方便记忆而采用简单易记的密码。这些密码往往仅包含简单的数字和字母&#xff0c;缺乏复杂性和多样性&#xff0c;因此极易被破解。弱口令的存在严重威胁到系统和用户的数据安全&#xff0c;使得攻击…

在局域网中的另一台主机如何访问windows10WSL中的服务

文章目录 1&#xff0c;开启win10 路由功能2&#xff0c;配置转发规则 1&#xff0c;开启win10 路由功能 2&#xff0c;配置转发规则 netsh advfirewall firewall add rule name"Allowing LAN connections" dirin actionallow protocolTCP localport80 netsh interf…

计算机体系结构:缓存一致性ESI

集中式缓存处理器结构&#xff08;SMP&#xff09; 不同核访问存储器时间相同。 分布式缓存处理器结构&#xff08;NUMA&#xff09; 共享存储器按模块分散在各处理器附近&#xff0c;处理器访问本地存储器和远程存储器的延迟不同&#xff0c;共享数据可进入处理器私有高速缓存…

程序员自曝接单:三年时间接了25个单子,收入12万

程序员接单在程序员的副业中并不少见。程序员接单作为一个起步快、门槛低、类型多样的副业选择&#xff0c;一直深受程序员的青睐。就算你没有接触过接单&#xff0c;也一定对接单有过了解。 程序员接单是指程序员通过接取开发者发布的项目或任务来获取收入的一种工作方式。程序…

“八股文”的江湖:助力、阻力还是空谈?深度解析程序员面试的敲门砖

一、引言&#xff1a;八股文的江湖——助力、阻力还是空谈&#xff1f; 1.1 八股文的定义与背景 八股文&#xff0c;原指我国明清时期科举考试的一种应试文体&#xff0c;因其固定模式和空洞内容而备受诟病。在当今的程序员面试中&#xff0c;程序员的“八股文”通常指的是在技…