【数据结构】_C语言实现不带头非循环单向链表

目录

1. 链表的概念及结构

2. 链表的分类

3. 单链表的实现

3.1 SList.h头文件

3.2 SList.c源文件

3.3 Test_SList.c测试文件


关于线性表,已介绍顺序表,详见下文:

【数据结构】_顺序表-CSDN博客

本文介绍链表;

基于顺序表的特点,思考改善方案:

按需申请释放空间,不再将数据存储于连续的一整块空间中,而是需要一个数据开辟一个小空间。为了方便访问数据,首先创建一个头指针(头结点)指向存放第一个数据的内存位置处,而在该位置处,除了存储该数据本身,再分配一块空间用于存放下一个数据的地址,直至某位置存放的下一个位置的指针为空则数据截止。

同时,这种存储方式也有效地提高了插入删除数据时的效率,无需再大量挪动数据。

这种数据结构就称为链表。

1. 链表的概念及结构

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表在逻辑上是连续的,在物理上不是连续的

2. 链表的分类

对于链表,有单向和双向、带头与不带头、循环与不循环的分类,不同的组合如下;

各种类型的链表示意图如下:

单向和双向:(区别标准:能从一个/两个方向遍历)

带头和不带头:(是否在第一个有效结点前增加一个头结点)

循环和非循环:(尾结点的next为NULL/指向第一个结点)

最常用的链表结构是:无头单向非循环链表带头双向循环链表

注:头结点并不是第一个有效结点,而是在第一个有效结点前再创建一个不存储有效数据的结点

3. 单链表的实现

3.1 SList.h头文件

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

// 链表结点
typedef int SLTDataType;
typedef struct SListNode {
	SLTDataType data;
	struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead);
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
SLTNode* SLTCreatNode(SLTDataType x);
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
// 在指定位置前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
// 在指定位置后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
// 删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos);
// 删除pos后的结点
void SLTEraseAfter(SLTNode* pos);
// 销毁
void SLTDestory(SLTNode** pphead);

3.2 SList.c源文件

#include"SList.h"
void SLTPrint(SLTNode* phead) {
	SLTNode* pcur = phead;
	while (pcur) {
		printf("%d-> ", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}
SLTNode* SLTCreatNode(SLTDataType x) {
	SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newNode == NULL) {
		perror("malloc fail\n");
		exit(1);
	}
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
	assert(pphead);
	SLTNode* newNode = SLTCreatNode(x);
	// 空链表
	if (*pphead == NULL) {
		*pphead = newNode;
	}
	else {
		// 非空链表
		SLTNode* curNode = *pphead;
		while (curNode->next) {
			curNode = curNode->next;
		}
		curNode->next = newNode;
	}
}
void SLTPushFront(SLTNode** pphead, SLTDataType x) {
	assert(pphead);
	SLTNode* newNode = SLTCreatNode(x);
	newNode->next = *pphead;
	// 令新结点为链表的头结点
	*pphead = newNode;
}
void SLTPopBack(SLTNode** pphead) {
	assert(pphead && *pphead);
	// 链表只有一个结点
	if ((*pphead)->next == NULL) {
		free(*pphead);
		*pphead = NULL;
	}
	// 链表有多个结点
	else {
		SLTNode* tailPrevNode = *pphead;
		SLTNode* tailNode = *pphead;
		while (tailNode->next) {
			tailPrevNode = tailNode;
			tailNode = tailNode->next;
		}
		free(tailNode);
		tailNode = NULL;
		tailPrevNode->next = NULL;
	}
}
void SLTPopFront(SLTNode** pphead) {
	assert(pphead && *pphead);
	SLTNode* secNode = (*pphead)->next;
	free(*pphead);
	*pphead = secNode;
}
SLTNode* SLTFind(SLTNode* phead, SLTDataType x) {
	SLTNode* curNode = phead;
	while (curNode) {
		if (curNode->data == x) {
			return curNode;
		}
		curNode = curNode->next;
	}
	return NULL;
}
// 在指定位置前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) {
	assert(pphead && *pphead && pos);
	SLTNode* newNode = SLTCreatNode(x);
	if (pos == *pphead) {
		// 调用头插方法
		SLTPushFront(pphead, x);
	}
	else {
		SLTNode* posPrevNode = *pphead;
		while (posPrevNode->next != pos) {
			posPrevNode = posPrevNode->next;
		}
		posPrevNode->next = newNode;
		newNode->next = pos;
	}
}
// 在指定位置后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
	assert(pos);
	SLTNode* newNode = SLTCreatNode(x);
	SLTNode* posAfterNode = pos->next;
	pos->next = newNode;
	newNode->next = posAfterNode;
}
// 删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos) {
	assert(pphead && *pphead && pos);
	if (*pphead == pos) {
		// 调用头删方法
		SLTPopFront(pphead);
	}
	else {
		SLTNode* posPrevNode = *pphead;
		while (posPrevNode->next != pos) {
			posPrevNode = posPrevNode->next;
		}
		posPrevNode->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
// 删除pos后的结点
void SLTEraseAfter(SLTNode* pos) {
	assert(pos && pos->next);
	SLTNode* posAfterNode = pos->next;
	pos->next = posAfterNode->next;
	free(posAfterNode);
	posAfterNode = NULL;
}
// 销毁
void SLTDestory(SLTNode** pphead) {
	assert(pphead && *pphead);
	SLTNode* curNode = *pphead;
	while (curNode) {
		SLTNode* curNextNode= curNode->next;
		free(curNode);
		curNode = NULL;
	}
	*pphead = NULL;
}

3.3 Test_SList.c测试文件

#include"SList.h"
void Test11() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTDestory(&plist);
	SLTPrint(plist);
}
void Test10() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTNode* aimNode1 = SLTFind(plist, 3);
	SLTEraseAfter(aimNode1);
	SLTPrint(plist);
	SLTNode* aimNode2 = SLTFind(plist, 1);
	SLTEraseAfter(aimNode2);
	SLTPrint(plist);
}
void Test9() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTNode* aimNode1 = SLTFind(plist, 3);
	SLTErase(&plist, aimNode1);
	SLTPrint(plist);
	SLTNode* aimNode2 = SLTFind(plist, 1);
	SLTErase(&plist, aimNode2);
	SLTPrint(plist);
}
void Test8() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTNode* aimNode1 = SLTFind(plist, 3);
	SLTInsertAfter(aimNode1, 85);
	SLTPrint(plist);
	SLTNode* aimNode2 = SLTFind(plist, 1);
	SLTInsertAfter(aimNode2, 97);
	SLTPrint(plist);
}
void Test7(){
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	SLTNode* aimNode1 = SLTFind(plist, 3);
	SLTInsert(&plist, aimNode1, 85);
	SLTPrint(plist);
	SLTNode* aimNode2 = SLTFind(plist, 1);
	SLTInsert(&plist, aimNode2, 97);
	SLTPrint(plist);
}
void Test6() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
	// SLTNode* aimNode = SLTFind(plist, 3);
	SLTNode* aimNode = SLTFind(plist, 6);
	if (aimNode == NULL)
		printf("Find nothing\n");
	else
		printf("Find successfully\n");
}
void Test5() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPrint(plist);
	SLTPopFront(&plist);
	SLTPrint(plist);
	SLTPopFront(&plist);
	SLTPrint(plist);
	SLTPopFront(&plist);
	SLTPrint(plist);
}
void Test4() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPrint(plist);
	SLTPopBack(&plist);
	SLTPrint(plist);
	SLTPopBack(&plist);
	SLTPrint(plist);
	SLTPopBack(&plist);
	SLTPrint(plist);
}
void Test3() {
	SLTNode* plist = NULL;
	SLTPushFront(&plist, 1);
	SLTPushFront(&plist, 2);
	SLTPushFront(&plist, 3);
	SLTPushFront(&plist, 4);
	SLTPrint(plist);
}
void Test2() {
	SLTNode* plist = NULL;
	SLTPushBack(&plist, 1);
	SLTPushBack(&plist, 2);
	SLTPushBack(&plist, 3);
	SLTPushBack(&plist, 4);
	SLTPrint(plist);
}

void Test1() {
	SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
	node1->data = 1;
	SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
	node2->data = 2;
	SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
	node3->data = 3;
	SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
	node4->data = 4;

	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = NULL;

	SLTNode* plist = node1;
	SLTPrint(plist);
}
int main() {
	//Test1();
	//Test2();
	//Test3();
	//Test4();
	//Test5();
	//Test6();
	//Test7();
	//Test8();
	//Test9();
	//Test10();
	Test11();
	return 0;
}

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

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

相关文章

HTML5 Web Worker 的使用与实践

引言 在现代 Web 开发中&#xff0c;用户体验是至关重要的。如果页面在执行复杂计算或处理大量数据时变得卡顿或无响应&#xff0c;用户很可能会流失。HTML5 引入了 Web Worker&#xff0c;它允许我们在后台运行 JavaScript 代码&#xff0c;从而避免阻塞主线程&#xff0c;保…

Excel 技巧21 - Excel中整理美化数据实例,Ctrl+T 超级表格(★★★)

本文讲Excel中如何整理美化数据的实例&#xff0c;以及CtrlT 超级表格的常用功能。 目录 1&#xff0c;Excel中整理美化数据 1-1&#xff0c;设置间隔行颜色 1-2&#xff0c;给总销量列设置数据条 1-3&#xff0c;根据总销量设置排序 1-4&#xff0c;加一个销售趋势列 2&…

手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion(原理介绍)

手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion&#xff08;原理介绍&#xff09; 目录 手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion&#xff08;原理介绍&#xff09;DDPM 原理图Stable Diffusion 原理Stable Diffusion的原理解释Stable Diffusion 和 Diffus…

倍频增量式编码器--角度插值法输出A,B(Aangular Interpolation)

问题是&#xff1a; 最大速度&#xff0c;周期刻度&#xff0c;最小细分刻度&#xff0c;可以计算得到&#xff1a; 结论&#xff1a; 按照最高速度采样&#xff1b;数字A,B输出间隔时间&#xff1a;按照计算角度 插入细分角度运算算时间&#xff08;最快速度&#xff09;&a…

基于微信小程序的助农扶贫系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

嵌入式C语言:结构体对齐

目录 一、对齐的原因 1.1. 硬件访问效率 1.2. 内存管理简化 1.3. 编译器优化 1.4. 代码示例 二、对齐规则 2.1. 基本数据类型对齐 2.2. 结构体成员对齐 2.3. 结构体整体对齐 2.4. 代码示例 三、对齐控制 3.1. 使用 #pragma pack 3.2. 使用 __attribute__((packed)…

网络工程师 (1)数据的表示

一、R进制的表示及互转 R进制是一种数制表示方法&#xff0c;其中R代表基数&#xff0c;采用R个基本符号&#xff08;0, 1, 2, …, R-1&#xff09;表示各位上的数字&#xff0c;并遵循“逢R进一”的运算规则。在R进制中&#xff0c;每一位上的数字均不超过R-1。R进制与十进制之…

coffee销售数据集分析:基于时间趋势分析的实操练习

**文章说明&#xff1a;**对coffee销售数据集的简单分析练习&#xff08;时间趋势分析练习&#xff09;&#xff0c;主要是为了强化利用python进行数据分析的实操能力。属于个人的练习文章。 **注&#xff1a;**这是我第一次使用md格式编辑博客文章&#xff0c;排版上还是不是很…

SQL在DBA手里-改写篇

背景 最近运营需要做月报汇总交易情况&#xff0c;之前一直是他们手工出的数据&#xff0c;他们想做成月初自动发送邮件&#xff0c;从而减轻他们的工作量。于是他们提供SQL我们在邮件服务器配置做定时发送任务。 表介绍&#xff08;表及字段已做脱敏处理&#xff09; trans…

vue3入门基础学习之搭建登录验证功能

环境准备&#xff1a;node.js、Visual Studio Code&#xff08;也可以是其他开发工具&#xff0c;选自己熟悉的就行&#xff09; 下载地址&#xff1a;https://nodejs.p2hp.com/https://code.visualstudio.com/ 新建一个vue3的项目&#xff0c;选一个文件夹执行以下命令 使用…

Scrapy如何设置iP,并实现IP重用, IP代理池重用

前置知识 1/3乐观锁 2/3 Scrapy流程(非全部) 3/3 关于付费代理 我用的"快代理", 1000个ip, 每个ip1min的有效期, 你用的时候, 把你的链接, 用户名填上去就行 设置代理IP &#x1f512; & 帮助文档: ①meta ②meta#proxy$ 语法: ①proxy的设置: Request对象中…

消息队列篇--通信协议篇--网络通信模型(OSI7层参考模型,TCP/IP分层模型)

一、OSI参考模型&#xff08;Open Systems Interconnection Model&#xff09; OSI参考模型是一个用于描述和标准化网络通信功能的七层框架。它由国际标准化组织&#xff08;ISO&#xff09;提出&#xff0c;旨在为不同的网络设备和协议提供一个通用的语言和结构&#xff0c;以…

开源智慧园区管理系统对比五款主流产品探索智能运营新模式

内容概要 在这个数字化迅速发展的时代&#xff0c;园区管理也迎来了全新的机遇和挑战。众所周知&#xff0c;开源智慧园区管理系统作为一种创新解决方案&#xff0c;正逐步打破传统管理的局限性。它的开放性不仅使得系统可以根据具体需求进行灵活调整&#xff0c;也为用户提供…

leetcode——删除链表的倒数第N个节点(java)

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#xf…

WPS数据分析000009

一、函数与数据透视表统计数据时效率差异 函数 F4绝对引用 数据透视表 二、数据透视表基础操作 数据透视表&#xff1a;一个快速的生成报表的工具 显示详细信息 方式一; 方式二&#xff1a; 移动数据透视表 删除数据透视表 复制粘贴数据透视表 留足空间&#xff0c;否则拖动字…

【C++图论】1761. 一个图中连通三元组的最小度数|2005

本文涉及知识点 C图论 LeetCode1761. 一个图中连通三元组的最小度数 给你一个无向图&#xff0c;整数 n 表示图中节点的数目&#xff0c;edges 数组表示图中的边&#xff0c;其中 edges[i] [ui, vi] &#xff0c;表示 ui 和 vi 之间有一条无向边。 一个 连通三元组 指的是 …

ubuntu 更新24LTS中断导致“系统出错且无法恢复,请联系系统管理员”

22LTS to 24LTS 更新过程中手jian把更新程序controlC导致的。 解决 目前企图完成更新来恢复&#xff0c;重启后有软件包冲突&#xff0c;sudo apt upgrade报冲突。无法进行。 将原来source.list重新 sudo dpkg --configure -a sudo apt install -f 这些都不管用。还是显示gno…

vscode环境中用仓颉语言开发时调出覆盖率的方法

在vscode中仓颉语言想得到在idea中利用junit和jacoco的覆盖率&#xff0c;需要如下几个步骤&#xff1a; 1.在vscode中搭建仓颉语言开发环境&#xff1b; 2.在源代码中右键运行[cangjie]coverage. 思路1&#xff1a;编写了测试代码的情况&#xff08;包管理工具&#xff09; …

C语言的灵魂——指针(1)

指针是C语言的灵魂&#xff0c;有了指针C语言才能完成一些复杂的程序&#xff1b;没了指针就相当于C语言最精髓的部分被去掉了&#xff0c;可见指针是多么重要。废话不多讲我们直接开始。 指针 一&#xff0c;内存和地址二&#xff0c;编址三&#xff0c;指针变量和地址1&#…

mantisbt添加修改用户密码

文章目录 问题当前版本安装流程创建用户修改密码老的方式探索阶段 问题 不太好改密码啊。貌似必须要域名要发邮件。公司太穷&#xff0c;看不见的东西不关心&#xff0c;只能改源码了。 当前版本 当前mantisbt版本 2.27 php版本 7.4.3 安装流程 &#xff08;下面流程不是…