单链表的实现(数据结构)

本篇博客主要是单链表(无头单项不循环)的实现的代码分享

说明:因为此单链表无头(哨兵位),可以说成没有初始化也可以说初始化时没有一个有效地址作为单链表的起始地址 例如下面代码中的plist == NULL。

  所以在后面函数(链表为空时,头插、尾插、插入)实现过程中需要将plist(单链表头结点地址)修改,就需要传址操作(在这里需要传单链表节点地址的地址),而且为了代码接口的一致性,在单链表函数实现中全部传了单链表节点地址的地址!

图解:

	SLNode* plist = NULL;//只是定义了一个单向链表节点的地址,而且地址还==NULL


	SLNodePushBack(&plist,1);

头文件Single List.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int SLNodeDataType;
typedef struct Single_Linked_ListNode
{
	SLNodeDataType data;
	struct Single_Linked_ListNode* next;
}SLNode;

//
void SLNodePushBack(SLNode** pphead, SLNodeDataType x);
void SLNodePushFront(SLNode** pphead, SLNodeDataType x);

void SLNodePopBack(SLNode** pphead);
void SLNodePopFront(SLNode** pphead);

SLNode* SLNodeBuyNode(SLNodeDataType x);
void SLNodePrint(SLNode** pphead);

SLNode* SLNodeFind(SLNode** pphead,SLNodeDataType x);

void SLNodeInsert(SLNode** pphead, SLNode* pos, SLNodeDataType x);
void SLNodeErase(SLNode** pphead, SLNode* pos);

void SLNodeInsertAfter(SLNode** pphead, SLNode* pos, SLNodeDataType x);
void SLNodeEraseAfter(SLNode** pphead, SLNode* pos);
     
void SListDestroy(SLNode** pphead)

源文件Single Link.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Single List.h"


SLNode* SLNodeBuyNode(SLNodeDataType x)
{
	SLNode* tmp = malloc(sizeof(SLNode));
	if (tmp == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	tmp->data = x;
	tmp->next = NULL;
	return tmp;
};
void SLNodePushBack(SLNode** pphead, SLNodeDataType x)
{
	assert(pphead);
	SLNode* pnewnode = SLNodeBuyNode(x);
	//链表为空,新节点做头节点
	if (*pphead == NULL)
	{
		*pphead = pnewnode;
		return;
	}

	//链表不为空,找尾节点
	SLNode* ptail= *pphead;
	while (ptail->next != NULL)
	{
		ptail = ptail->next;
	}
	ptail->next = pnewnode;

	
};
void SLNodePushFront(SLNode** pphead, SLNodeDataType x)
{
	assert(pphead);
	SLNode* pnewnode = SLNodeBuyNode(x);
	//链表为空,新节点做头节点
	if (*pphead == NULL)
	{
		*pphead = pnewnode;
		return;
	}
	//链表不为空
	pnewnode->next = *pphead;
	*pphead = pnewnode;

}

void SLNodePopBack(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);//确保有节点
	//只有一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);//置空前不要忘了释放空间
		*pphead = NULL;
		return;//不需要再走了
	}
	//多节点,找尾节点前一个节点
	SLNode* ptailprev = *pphead;
	while ((ptailprev->next->next) != NULL)
	{
		ptailprev = ptailprev->next;
	}
	free(ptailprev->next);
	ptailprev->next = NULL;

}
void SLNodePopFront(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);//必须有节点
	一个节点
	//if ((*pphead)->next == NULL)
	//{
	//	free(*pphead);
	//	*pphead = NULL;
	//	return;
	//}
	多个节点
	SLNode* tmp = (*pphead)->next;
	free(*pphead);
	*pphead = tmp;

}


void SLNodePrint(SLNode** pphead)
{
	SLNode* pcur = *pphead;
	while (pcur)
	{
		printf("%d->",pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}

SLNode* SLNodeFind(SLNode** pphead,SLNodeDataType x)
{
	assert(pphead);
	//遍历链表
	SLNode* pcur = *pphead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur=pcur->next;
	}
	//没找到
	return NULL;
}
void SLNodeInsert(SLNode** pphead, SLNode* pos, SLNodeDataType x)
{
	assert(pphead);
	assert(pos);
	//链表不为空
	assert(*pphead);
	SLNode* pnewnode = SLNodeBuyNode(x);
	//头节点插入
	if (pos == *pphead)
	{
		SLNodePushFront(pphead,x);
		return;
	}
	//其他节点

	SLNode* prev = *pphead;
	while (prev->next!=pos)
	{
		prev = prev->next;
	}
	prev->next = pnewnode;
	pnewnode->next = pos;
}
void SLNodeErase(SLNode** pphead, SLNode* pos)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);

	if (*pphead == pos)
	{  
		SLNodePopFront(pphead);
		return;
	}
	SLNode* prev= *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	SLNode* pnext = pos->next;
	pos->next = NULL;
	free(pos);
	pos = NULL;
	prev -> next = pnext;
}

void SLNodeInsertAfter(SLNode** pphead, SLNode* pos, SLNodeDataType x)
{
	
	assert(pphead);
	assert(pos);
	SLNode* pnewnode = SLNodeBuyNode(x);
	SLNode* pnext = pos->next;
	pos->next = pnewnode;
	pnewnode->next = pnext;


}
void SLNodeEraseAfter(SLNode** pphead, SLNode* pos)
{

	assert(pphead);
	assert(pos);
	assert(pos->next);
	//pos pnext pnextnext
	SLNode* pnext = pos->next;
	SLNode* pnextnext = pnext->next;
	pos->next = pnextnext;
	pnext->next = NULL;
	free(pnext);
	pnext = NULL;

}

void SListDestroy(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);

	SLNode* pcur = *pphead;
	while (pcur)
	{
		SLNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

测试test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Single List.h"



int main()
{
	SLNode* plist = NULL;
	SLNodePushBack(&plist,1);
	SLNodePushBack(&plist,2);
	SLNodePushBack(&plist,3);
	SLNodePushBack(&plist,4);
	SLNodePushBack(&plist,5);

	SLNodePrint(&plist);
	SLNodePushFront(&plist, 100);
	SLNodePushFront(&plist, 200);
	SLNodePushFront(&plist, 300);
	SLNodePushFront(&plist, 400);
	SLNodePrint(&plist);
	SLNodePopBack(&plist);
	SLNodePopBack(&plist);



	SLNodePrint(&plist);
	SLNodePopFront(&plist);
	SLNodePopFront(&plist);
	SLNodePopFront(&plist);


	SLNodePrint(&plist);
	SLNode* findinex = SLNodeFind(&plist,100 );
	if (findinex)
	{
		printf("找到了\n");
	}
	else
	{
		printf("未找到\n");
	}
	SLNodeInsert(&plist,findinex,1000);
	SLNodePrint(&plist);
	SLNodeErase(&plist,findinex);
	SLNodePrint(&plist);
	SLNode* findinex2 = SLNodeFind(&plist, 1000);
	if (findinex2)
	{
		printf("找到了\n");
	}
	else
	{
		printf("未找到\n");
	}
	//SLNodeErase(&plist, findinex2);
	SLNodePrint(&plist);
	SLNodeInsertAfter(&plist, findinex2, 666);
	SLNodePrint(&plist);
	SLNode* findinex3 = SLNodeFind(&plist,1000);
	if (findinex3)
	{
		printf("找到了\n");
	}
	else
	{
		printf("未找到\n");
	}
	SLNodeEraseAfter(&plist, findinex3);
	SLNodePrint(&plist);
	return 0;
	SListDestroy(&plist);
}

这个博客如果对你有帮助,给博主一个免费的点赞就是最大的帮助

欢迎各位点赞,收藏和关注哦

如果有疑问或有不同见解,欢迎在评论区留言哦

后续我会一直分享双一流211西北大学本科生我自己的软件学习过程(C,数据结构,C++,Linux,MySQL)的学习干货以

及重要代码的分享

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

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

相关文章

DEYO: DETR with YOLO for End-to-End Object Detection论文翻译

DEYO&#xff1a;DETR与YOLO用于端到端目标检测 摘要 DETR的训练范式在很大程度上取决于在ImageNet数据集上预训练其骨干。然而&#xff0c;由图像分类任务和一对一匹配策略提供的有限监督信号导致DETR的预训练不充分的颈部。此外&#xff0c;在训练的早期阶段匹配的不稳定性会…

iStoreOS系统内安装HomeAssistant服务

iStoreOS系统内安装HomeAssistant服务 1. HomeAssistant服务 HomeAssistant是一款基于Python的开源智能家居系统&#xff0c;简称HA。 HomeAssistant可以方便地连接各种外部设备&#xff0c;如智能设备、摄像头、邮件、短消息和云服务等&#xff0c;其成熟的可连接组件有近千…

【重温设计模式】迭代器模式及其Java示例

迭代器模式的介绍 在编程领域&#xff0c;迭代器模式是一种常见的设计模式&#xff0c;它提供了一种方法&#xff0c;使得我们可以顺序访问一个集合对象中的各个元素&#xff0c;而又无需暴露该对象的内部表示。你可以把它想象成一本书&#xff0c;你不需要知道这本书是怎么印…

最佳牛围栏(二分 + 前缀和)

最佳牛围栏 原题链接&#xff1a;https://www.acwing.com/problem/content/104/ 题目 思路 我们发现若是枚举答案的话&#xff0c;那么我们判断是否存在一个平均值大于等于mid&#xff0c;如果最优解是x&#xff0c;那么mid < x的时候&#xff0c;必然可以找到一段&#x…

二十七 超级数据查看器 讲解稿 APP的用途 能做什么

二十七 超级数据查看器 讲解稿 APP的用途 能做什么 ​ 点击此处 访问B站 以新页面观看教学视频 点击此处 访问豌豆荚 下载APP 讲解稿全文: 大家好&#xff0c;今天我们讲一下超级数据查看器 的用途 也就是讲软件有什么用&#xff0c;能做什么&#xff0c;应用场景&#xff0…

mongo和redis的数据备份和还原

redis 安装 Redis安装和基本使用&#xff08;windows版&#xff09; - 知乎 window环境下Redis7服务器的安装和运行_redis7 windows-CSDN博客 备份数据 Redis SAVE 命令用于创建当前数据库的备份。 该命令将在 redis 安装目录中创建dump.rdb文件 查询路径 CONFIG GET dir…

SAR ADC学习笔记(4)

CDAC电容阵列 一、电容失配 二、电容失配对CDAC线性度的影响 1.电容失配对DNL的影响 2.电容失配对INL的影响 三、分段结构的CDAC 四、CDAC开关切换方案&#xff1a;传统开关切换策略 第一次比较阶段&#xff1a;如果VP(1)-VN(1)<0 第一次比较阶段&#xff1a;如果VP(1)-VN…

金融行业专题|基金超融合架构转型与场景探索合集(2023版)

更新内容 更新 SmartX 超融合在基金行业的覆盖范围、部署规模与应用场景。更新信创云资源池、关键业务系统性能优化等场景实践。更多超融合金融核心生产业务场景实践&#xff0c;欢迎下载阅读电子书《金融核心生产业务场景探索文章合集》。 随着数字化经济的蓬勃发展&#xf…

(学习总结)如何使用ChatGPT API训练自定义知识库

第一步&#xff1a; 安装OpenAI、GPT Index、PyPDF2和Gradio库 pip install openai pip install gpt_index pip install PyPDF2 pip install gradio 第二步&#xff1a;用VScode代码编辑器写app.py代码 记得替换api密钥 from llama_index import SimpleDirectoryReader, …

Cloud-Eureka服务治理-Ribbon负载均衡

构建Cloud父工程 父工程只做依赖版本管理 不引入依赖 pom.xml <packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEA…

DFS回溯-经典全排列问题(力扣)

前言 对于全排列问题&#xff0c;常用的做法是设置一个vis数组来确定位置i上的数字是否被访问&#xff0c;因为是全排列问题&#xff0c;所以不同的顺序也是不一样的排列&#xff0c;因此每次都是从起点开始询问**(注意起点到底是0还是1)** 46全排列(最简单的模板) class So…

Solidworks界面左边FeatureManager/设计树/模型树/树区域/零件树/零件栏不见了

Solidworks界面左边FeatureManager/设计树/模型树/树区域/零件树/零件栏不见了&#xff0c;按F9还原/隐藏&#xff0c;有的笔记本按FnF9

Gin 获取请求参数

POST 请求参数 Gin 获取Post请求URL参数有三种方式 func (c *Context) PostForm(key string) string func (c *Context) DefaultPostForm(key, defaultValue string) string func (c *Context) GetPostForm(key string) (string, bool)大多数情况下使用的是application/x-www…

ffmpeg maxrate 导致转码输出的内容包含随机性

https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate 问题 领导提出了一个问题&#xff0c;为什么转码后的视频大小字节数据都不一样&#xff0c;这问到我了&#xff0c;一时语塞。查一下吧&#xff0c;没有什么资料支撑。主动试一下。 尝试 首先尝试一下直接…

安卓 OpenGL ES 学习笔记

文章目录 OpenGL 学习笔记OpenGL 是什么&#xff1f;OpenGL ES是什么&#xff1f;怎么用&#xff1f;hello world如何实现动画效果 参考文章 OpenGL 学习笔记 OpenGL 是什么&#xff1f; OpenGL&#xff08;Open Graphics Library&#xff09;是一个跨平台的图形编程接口&…

EMMC的介绍

1、emmc的含义 eMMC (Embedded Multi Media Card)是MMC协会订立、主要针对手机或平板电脑等产品的内嵌式存储器标准规格。eMMC在封装中集成了一个控制器&#xff0c;提供标准接口并管理闪存&#xff0c;使得手机厂商就能专注于产品开发的其它部分&#xff0c;并缩短向市场推出产…

ChatGPT提示技巧——零,一和少量示例提示

ChatGPT提示技巧——零&#xff0c;一和少量示例提示 ​ 零样本(zero-shot)、少样本(few-shot)和单样本(one-shot)提示是用于在最少或没有示例的情况下从ChatGPT生成文本的技巧。这些技巧用于当某个具体任务有限定数据的时候或者任务是新的并且没有很好的定义的时候。 提示格…

吴恩达deeplearning.ai:数据增强数据合成迁移学习

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 让我们看看为你的程序添加数据的技巧。在构建神经网络的时候&#xff0c;我们总是想要更多的数据&#xff0c;但是获取更多的数据往往是十分昂贵又缓慢的。相反地&#xff0c;添加数据的另一…

例行性工作(at,crontab)

目录 单一执行的例行性工作at 语法 选项 时间格式 at的工作文件存放目录 at工作的日志文件 实例 命令总结&#xff1a; 循环执行的例行性工作crond 语法 选项 crontab工作调度对应的系统服务 crontab工作的日志文件 用户定义计划任务的文件所在目录 动态查看 crontab文件格式 文…

ThreadLocal, InheritableThreadLocal和TransmittableThreadLocal

ThreadLocal, InheritableThreadLocal和TransmittableThreadLocal ThreadLocal(TL) 后续部分地方会使用ThraedLocal简称为TL 什么是TL? ThreadLocal是Java中的一个类, 也称为线程本地变量, 它提供了线程局部变量的功能。每个ThreadLocal对象都可以存储一个线程本地的变量副…