单链表详解(附图解,结尾附全部源码)

下面开始带大家对单链表的增删查改进行图解

首先给大家介绍一下链表

链表就是每一个结构体中包含一个数据和一个结构体指针,这个指针就相当于锁链的作用将下一个结构体给锁住,但是每个结构体的空间是相对独立的。

图解:

1 首先实现尾插

如果我们要尾插,那就要把尾节点找到,然后用next指针进行连接

图解:

下面是代码实现

这里我考虑了一种特殊情况,就是如果链表为空的时候,我们就直接让头节点链接上。

这里必须要用到二阶指针来判定第一个节点是否为空的状态。

(如果用一阶指针的话,那么出了这个函数的作用域之后空间被销毁了,相当于你白忙活了)

每次用完记得把空间释放掉,不然存在内存泄漏

SL* BuyNewnode(DataSL x)
{
	SL* Newnode = (SL*)malloc(sizeof(SL));
	if (Newnode==NULL)
	{
		perror("malloc");
		assert(Newnode);
	}
	Newnode->data = x;
	Newnode->next = NULL;
	return Newnode;
}


void DistorySL(SL** pphead)
{
    SL* tail = *pphead;
	if (tail)
		return;
	else
	{
		while (tail->next)
		{
			SL* cur = tail->next;
			tail->next = NULL;
			tail->data = 0;
			free(tail);
			tail = cur;
		}
		tail->next = NULL;
		tail->data = 0;
		free(tail);
	}
}


void BackPushSL(SL** pphead, DataSL x)//尾插
{
	SL* tail = *pphead;
	SL* Newnode = BuyNewnode(x);
	if (tail == NULL)
	{
		*pphead = Newnode;
	}
	else
	{
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = Newnode;
	}
}

2 然后实现尾删

void BackPopSL(SL** pphead)//尾删
{
	assert(pphead);
	assert(*pphead);//空链表不删
	SL* tail = *pphead;
	if (tail->next==NULL)
	{
		tail->data = 0;
		free(tail);
	}
	else
	{
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

3 然后实现头插

void FrontPushSL(SL** pphead, DataSL x)
{
	assert(pphead);
	SL* tail = *pphead;
	SL* Newnode= BuyNewnode(x);
	if (tail == NULL)
	{
		tail = BuyNewnode(x);
	}
	else
	{
		Newnode->next = tail;
	}
	*pphead = Newnode;
}

4 然后实现头删

void FrontPopSL(SL** pphead)
{
	assert(pphead);
	SL* tail = (*pphead)->next;
	free(*pphead);
	(*pphead)->next = NULL;
	*pphead = tail;
}

5 然后实现中间插入(配合查找)

中间插入分两种情况前插和后插

SL* FindSL(SL** pphead, DataSL x)
{
	SL* tail = *pphead;
	while (tail)
	{
		if (tail->data == x)
		{
			break;
		}
		else
		{
			tail = tail->next;
		}
	}
	return tail;
}


void FrontInsertSL(SL** pphead,SL* pos,DataSL x)
{
	assert(pphead);
	assert(pos);
	SL* tail = *pphead;
	SL* Newnode = BuyNewnode(x);
	SL* cur = tail;
	if (*pphead == NULL)
	{
		FrontPushSL(&tail,x);
	}
	while (tail!= pos)
	{
		cur = tail;
		tail = tail->next;
	}
	cur->next = BuyNewnode(x);
	cur->next->next = pos;
}

后插的情况类似

SL* FindSL(SL** pphead, DataSL x)
{
	SL* tail = *pphead;
	while (tail)
	{
		if (tail->data == x)
		{
			break;
		}
		else
		{
			tail = tail->next;
		}
	}
	return tail;
}



void AfterInsertSL(SL** pphead, SL* pos, DataSL x)
{
	assert(pphead);
	assert(pos);
	SL* Newnode = BuyNewnode(x);
	SL* tail = *pphead;
	while (tail != pos)
	{
		tail = tail->next;
	}
	SL* cur = tail->next;
	tail->next = Newnode;
	Newnode->next = cur;
}

6 接着实现查删节点(原理和上面差不多,大家可以自行画图)

void EraseSL(SL** pphead, SL* pos)
{
	assert(pphead);
	assert(pos);
	SL* tail = *pphead;
	if (tail==pos)
	{
		BackPopSL(tail);
	}
	else
	{
		while (tail->next != pos)
		{
			tail = tail->next;
		}
	SL* cur = tail->next;
	tail->next = tail->next->next;
	cur->data = 0;
	cur->next = NULL;
	free(cur->next);
	}
}

7 最后实现改某个节点的内容

void ReviseSL(SL** pphead, SL* pos, DataSL x)
{
	assert(pphead);
	assert(pos);
	SL* tail = *pphead;
	if (tail== pos)
	{
		tail->data = x;
	}
	else
	{
		while (tail->next != pos)
		{
			tail = tail->next;
		}
		tail->next->data = x;
	}
}

下面附所有的源码

SingleSeqList.h

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

//开辟节点
SL* BuyNewnode(DataSL x);
//打印单链表的值
void SLPrint(SL* pphead);
//销毁链表
void DistorySL(SL** pphead);

singleSeqList.h

//对链表的增删查改
//头插尾插,头删尾删
void BackPushSL(SL** pphead,DataSL x);
void BackPopSL(SL** pphead);

void FrontPopSL(SL** pphead);
void FrontPushSL(SL** pphead, DataSL x);

//前插
void FrontInsertSL(SL** pphead,SL* pos,DataSL x);


//后插
void AfterInsertSL(SL** pphead, SL* pos, DataSL x);



//查找节点
SL* FindSL(SL** pphead, DataSL x);

//删除某个节点
void EraseSL(SL** pphead, SL* pos);

//修改某个节点的内容
void ReviseSL(SL** pphead, SL* pos, DataSL x);


SingleSeqList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SingleSqList.h"


void SLPrint(SL** pphead)
{
	SL* tail = *pphead;
	if (tail == NULL)
	{
		return;
	}
	while (tail->next)
	{
		printf("%d->", tail->data);
		tail = tail->next;
	}
	printf("%d", tail->data);
}

void DistorySL(SL** pphead)
{
    SL* tail = *pphead;
	if (tail)
		return;
	else
	{
		while (tail->next)
		{
			SL* cur = tail->next;
			tail->next = NULL;
			tail->data = 0;
			free(tail);
			tail = cur;
		}
		tail->next = NULL;
		tail->data = 0;
		free(tail);
	}
}




SL* BuyNewnode(DataSL x)
{
	SL* Newnode = (SL*)malloc(sizeof(SL));
	if (Newnode==NULL)
	{
		perror("malloc");
		assert(Newnode);
	}
	Newnode->data = x;
	Newnode->next = NULL;
	return Newnode;
}


void BackPushSL(SL** pphead, DataSL x)//尾插
{
	assert(pphead);
	SL* tail = *pphead;
	SL* Newnode = BuyNewnode(x);
	if (tail == NULL)
	{
		*pphead = Newnode;
	}
	else
	{
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = Newnode;
	}
}


void BackPopSL(SL** pphead)//尾删
{
	assert(pphead);
	assert(*pphead);//空链表不删
	SL* tail = *pphead;
	if (tail->next==NULL)
	{
		tail->data = 0;
		free(tail);
	}
	else
	{
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

void FrontPushSL(SL** pphead, DataSL x)
{
	assert(pphead);
	SL* tail = *pphead;
	SL* Newnode= BuyNewnode(x);
	if (tail == NULL)
	{
		tail = BuyNewnode(x);
	}
	else
	{
		Newnode->next = tail;
	}
	*pphead = Newnode;
}


void FrontPopSL(SL** pphead)
{
	assert(pphead);
	SL* tail = (*pphead)->next;
	free(*pphead);
	(*pphead)->next = NULL;
	*pphead = tail;
}


SL* FindSL(SL** pphead, DataSL x)
{
	SL* tail = *pphead;
	while (tail)
	{
		if (tail->data == x)
		{
			break;
		}
		else
		{
			tail = tail->next;
		}
	}
	return tail;
}



void FrontInsertSL(SL** pphead,SL* pos,DataSL x)
{
	assert(pphead);
	assert(pos);
	SL* tail = *pphead;
	SL* Newnode = BuyNewnode(x);
	SL* cur = tail;
	if (*pphead == NULL)
	{
		FrontPushSL(&tail,x);
	}
	while (tail!= pos)
	{
		cur = tail;
		tail = tail->next;
	}
	cur->next = BuyNewnode(x);
	cur->next->next = pos;
}

void AfterInsertSL(SL** pphead, SL* pos, DataSL x)
{
	assert(pphead);
	assert(pos);
	SL* Newnode = BuyNewnode(x);
	SL* tail = *pphead;
	while (tail != pos)
	{
		tail = tail->next;
	}
	SL* cur = tail->next;
	tail->next = Newnode;
	Newnode->next = cur;
}


void EraseSL(SL** pphead, SL* pos)
{
	assert(pphead);
	assert(pos);
	SL* tail = *pphead;
	if (tail==pos)
	{
		BackPopSL(tail);
	}
	else
	{
		while (tail->next != pos)
		{
			tail = tail->next;
		}
	SL* cur = tail->next;
	tail->next = tail->next->next;
	cur->data = 0;
	cur->next = NULL;
	free(cur->next);
	}
}


void ReviseSL(SL** pphead, SL* pos, DataSL x)
{
	assert(pphead);
	assert(pos);
	SL* tail = *pphead;
	if (tail== pos)
	{
		tail->data = x;
	}
	else
	{
		while (tail->next != pos)
		{
			tail = tail->next;
		}
		tail->next->data = x;
	}
}


链表每个功能我基本都实现了一遍这里就不一一的展现。(目前测试还未遇到问题)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智能优化算法应用:基于热交换算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于热交换算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于热交换算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.热交换算法4.实验参数设定5.算法结果6.参考文…

服务端监控工具:Nmon使用方法

一、认识nmon 1、简介 nmon是一种在AIX与各种Linux操作系统上广泛使用的监控与分析工具&#xff0c;它能在系统运行过程中实时地捕捉系统资源的使用情况&#xff0c;记录的信息比较全面&#xff0c; 并且能输出结果到文件中&#xff0c;然后通过nmon_analyzer工具产生数据文件…

spring 笔记九 Spring AOP

Spring 的 AOP 简介 什么是AOP AOP 为Aspect Oriented Programming 的缩写&#xff0c;意思为面向切面编程&#xff0c;是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 AOP 是OOP 的延续&#xff0c;是软件开发中的一个热点&#xff0c;也是Spring框架…

10 新字符设备驱动文件

一、新字符设备驱动原理 因为 register_chrdev 和 unregister_chrdev 两个函数是老版本驱动文件&#xff0c;现在可以用新字符设备驱动 API 函数。 1. 分配和和释放设备号 使用 register_chrdev 函数注册字符设备的时候只需要给定一个主设备号即可&#xff0c;但是这样会带来两…

【Kubernetes】存储类StorageClass

存储类StorageClass 一、StorageClass介绍二、安装nfs provisioner&#xff0c;用于配合存储类动态生成pv2.1、创建运行nfs-provisioner需要的sa账号2.2、对sa授权2.3、安装nfs-provisioner程序 三、创建storageclass&#xff0c;动态供给pv四、创建pvc&#xff0c;通过storage…

Mybatis-plus是使用,告别繁琐的CRUD编写,自动生成直接使用

目录 一、简介 1. 是什么 2. 特性 3. 框架结构 4. 常用注解 二、搭建使用 1. 依赖 2. 生成器 3. 生成 4. 引用 5. 路径访问 三、测试 四、雪花ID 每篇一获 Mybatis-plus&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;…

贪心算法:买卖股票的最佳时机II 跳跃游戏 跳跃游戏II

122.买卖股票的最佳时机II 思路&#xff1a; 想要获得利润&#xff0c;至少要以两天为一个交易单元&#xff0c;因为两天才会有股价差。因此可以将最终利润进行分解&#xff0c;如prices[3] - prices[0] (prices[3] - prices[2]) (prices[2] - prices[1]) (prices[1] - pr…

运筹学经典问题(二):最短路问题

问题描述 给定一个图&#xff08;有向图或无向图&#xff09; G ( V , E ) G (V, E) G(V,E)&#xff0c; V V V是图中点的集合&#xff0c; E E E是图中边的集合&#xff0c;图中每条边 ( i , j ) ∈ E (i, j) \in E (i,j)∈E都对应一个权重 c i j c_{ij} cij​&#xff08;…

nodejs+vue+微信小程序+python+PHP技术下的音乐推送系统-计算机毕业设计推荐

3.2.1前台用户功能 前台注册用户的功能如下&#xff1a; 注册登录&#xff1a;用户填写个人信息&#xff0c;并验证手机号码进行账户注册&#xff0c;注册成功后方可登录系统。 歌手介绍&#xff1a;用户可以在线进行歌手介绍信息查看等。 音乐库&#xff1a;用户可以在音乐库查…

【QT】非常简单的登录界面实现

本系列是作者自学实践过程的记录 本文是关于登录界面设计 有问题欢迎讨论 效果图&#xff1a; 一、创建项目和主界面 创建Qt Widget Application 这里我们使用qmake而不是cmake 这是主界面&#xff0c;登录界面等后面再创建&#xff0c;这里要勾选上generate form&#xff0…

网站转换APP源代码 WebAPP源代码 网站生成APP源代码 Flutter项目 带控制端

源码介绍 一款网站转换成APP的源代码,开发语言使用Flutter,开发工具使用的是AndroidStudio,你只需要在APP源代码里面填写你的域名,即可生成即可生成APP,包括安卓或者苹果,与此同时我们提供了APP的控制端.你可以通过控制端设置APP的颜色、添加APP的图标、添加APP的菜单栏目。 …

mybatis-plus使用达梦数据库处理枚举类型报错的问题

使用mybatis-plus连接达梦数据库&#xff0c;枚举类型无法读取 枚举类&#xff1a; 实体&#xff1a; 数据库字段&#xff1a; mybatis-plus枚举包配置&#xff1a; 调用查询方法&#xff1a; List<QualityRuleTemplate> qualityRuleTemplates ruleTemplateServic…

C#教程(三):字符串的各种用法

在C#中&#xff0c;字符串&#xff08;string 类型&#xff09;是一种常用的数据类型&#xff0c;用于存储和操作文本数据。以下是一些C#中字符串的常见用法 1、输出任意的字符串长度 代码 #region 输出任意的字符串长度 Console.WriteLine("请输入你心中想到的名字&…

玩转树莓派之系统安装篇

介绍 树莓派是树莓派基金会下的一个明星产品&#xff08;单板计算机&#xff09;&#xff0c;已经迭代到第五代了&#xff1b;它性能强大、开源、拓展性强、体积小&#xff0c;搞物联网开发的人基本都听说过这个玩意&#xff01;笔者手上刚好有一块4B的板子&#xff0c;让我们…

系统安全-应用威胁风险检查项及预防方案

系统安全-应用威胁风险检查项及预防方案 1、欺骗&#xff08;认证&#xff09; 2、篡改&#xff08;授权和加密&#xff09; 3、抵赖&#xff08;日志记录和数字签名&#xff09; 4、信息泄露&#xff08;敏感信息保护&#xff09; 5、特权提升 6、拒绝服务&#xff08;数据稀释…

【C语言】详解文件操作

&#xff08;零&#xff09;引入 终端是计算机系统中与用户进行交互的界面。 在以往的程序中&#xff0c;我们通过终端用键盘输入数据&#xff0c;通过屏幕输出信息。 但是&#xff0c;如果我们不想手动低效地输入数据&#xff0c;而是通过文件一次性高效输入&#xff1b; 如果…

网络基础3

NAT&#xff08;Network Address Translation&#xff09;&#xff1a;网络地址转换 通过将内部网络的私有IP地址装换成全球唯一的公网IP地址&#xff0c;使内部网络可以连接到互联网。 广域网就是外网&#xff0c;局域网就是内网 私有IP地址&#xff1a;&#xff08;如果是纯内…

【MyBatis-Plus】简化你的Java持久层开发

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于MyBatis-Plus的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.MyBatis-Plus是什么 二.MyBati…

深入解析 Spring 和 Spring Boot 的区别

目录 引言 1. 设计理念 1.1 Spring 框架的设计理念 1.2 Spring Boot 的设计理念 2. 项目配置 2.1 Spring 框架的项目配置 2.2 Spring Boot 的项目配置 3. 自动配置 3.1 Spring 框架的自动配置 3.2 Spring Boot 的自动配置 4. 微服务支持 4.1 Spring 框架的微服务支持…

《工程数值计算Python教程》笔记

文章目录 [toc]第一章&#xff1a;绪论 1.1 1.1 1.1|数值计算在工程科学中的重要性 1.2 1.2 1.2|数值计算方法 1.3 1.3 1.3|程序设计盒图计算方法的选取减少运算次数避免相近的数相减 1.4 1.4 1.4|误差的来源、表示及传递误差的来源和分类模型误差观测误差截断误差舍入误差 误差…