【数据结构】_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");elseprintf("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;
}
相关文章:
【数据结构】_C语言实现不带头非循环单向链表
目录 1. 链表的概念及结构 2. 链表的分类 3. 单链表的实现 3.1 SList.h头文件 3.2 SList.c源文件 3.3 Test_SList.c测试文件 关于线性表,已介绍顺序表,详见下文: 【数据结构】_顺序表-CSDN博客 本文介绍链表; 基于顺序表…...
【Qt】06-对话框
对话框 前言一、模态和非模态对话框1.1 概念1.2 模态对话框1.2.1 代码QAction类 1.2.2 模态对话框运行分析 1.3 非模态对话框1.3.1 代码局部变量和成员变量setAttribute 类 1.3.2 现象解释 二、标准对话框2.1 提示对话框 QMessageBox2.1.1 现象及解释 2.2 问题对话框2.2.1 现象…...
特征缩放:数据归一化
First,新年到了!感谢CSDN一路相伴,成为技术交流的温馨港湾。值此蛇年新春,祝平台人气蒸蒸日上,活动精彩纷呈,助力更多开发者突破技术瓶颈,在新的一年创造无限可能,新年快乐ÿ…...
Kubernetes 环境中的自动化运维实战指南
Kubernetes 作为容器编排领域的领导者,已经成为云原生应用的核心基础设施。然而,随着集群规模的扩大和应用的复杂化,手动运维 Kubernetes 集群变得愈发困难。自动化运维成为提升效率、保障系统稳定性的关键。本文将详细介绍如何在 Kubernetes 环境中实施自动化运维,涵盖工具…...
深入探讨Web应用开发:从前端到后端的全栈实践
在数字化时代,Web应用已成为连接用户与服务的关键桥梁。无论是电商平台、社交媒体,还是企业内部管理系统,Web应用都扮演着不可或缺的角色。本文将深入探讨Web应用开发的全栈实践,从前端的用户体验设计到后端的数据处理与存储&…...
分享|通过Self-Instruct框架将语言模型与自生成指令对齐
结论 在大型 “指令调整” 语言模型依赖的人类编写指令数据存在数量、多样性和创造性局限, 从而阻碍模型通用性的背景下, Self - Instruct 框架, 通过 自动生成 并 筛选指令数据 微调预训练语言模型, 有效提升了其指令遵循能…...
扣子平台音频功能:让声音也能“智能”起来。扣子免费系列教程(14)
在数字化时代,音频内容的重要性不言而喻。无论是在线课程、有声读物,还是各种多媒体应用,音频都是传递信息、增强体验的关键元素。扣子平台的音频功能,为开发者和内容创作者提供了一个强大而灵活的工具,让音频的使用和…...
超分辨率体积重建实现术前前列腺MRI和大病理切片组织病理学图像的3D配准
摘要: 磁共振成像(MRI)在前列腺癌诊断和治疗中的应用正在迅速增加。然而,在MRI上识别癌症的存在和范围仍然具有挑战性,导致即使是专家放射科医生在检测结果上也存在高度变异性。提高MRI上的癌症检测能力对于减少这种变异性并最大化MRI的临床效用至关重要。迄今为止,这种改…...
C++并发编程指南03
文章目录 传递参数2.2.1 基本参数传递示例: 2.2.2 注意动态变量指针的传递错误示例:正确示例: 2.2.3 引用参数的传递错误示例:正确示例: 2.2.4 成员函数和对象指针的传递示例:带参数的成员函数示例…...
大数据Hadoop入门3
目录 第五部分(Apache Hive DML语句和函数使用) 1.课程内容大纲和学习目标 2.Hive SQL-DML-load加载数据操作 3.Hive SQL-DML-insert插入数据 4.Hive SQL-DML-select查询-语法书和环境准备 5.Hive SQL-DML-select查询-列表达式和distinct去重 6.Hi…...
Autosar-Os是怎么运行的?(多核系统运行)
写在前面: 入行一段时间了,基于个人理解整理一些东西,如有错误,欢迎各位大佬评论区指正!!! 目录 1.Autosar多核操作系统 1.1多核启动过程 1.2多核运行过程 1.2.1核间任务同步 1.2.2Counte…...
【硬件介绍】三极管工作原理(图文+典型电路设计)
什么是三极管? 三极管,全称为双极型晶体三极管,是一种广泛应用于电子电路中的半导体器件。它是由三个掺杂不同的半导体材料区域组成的,这三个区域分别是发射极(E)、基极(B)和集电极&…...
MATLAB基础应用精讲-【数模应用】DBSCAN算法(附MATLAB和python代码实现)
目录 前言 几个高频面试题目 DBSCAN和传统聚类算法对比 算法原理 发展历程 主要事件 发展分析 什么是DBSCAN DBSCAN算法的聚类过程 DBSCAN算法的样本点组成 几个相关的概念: 算法思想 DBSCAN算法优缺点和改进 2.1 DBSCAN算法优缺点 2.2 DBSCAN算法改进 算法流…...
STM32 PWM驱动舵机
接线图: 这里将信号线连接到了开发板的PA1上 代码配置: 这里的PWM配置与呼吸灯一样,呼吸灯连接的是PA0引脚,输出比较单元用的是OC1通道,这里只需改为OC2通道即可。 完整代码: #include "servo.h&quo…...
基于Go语言的三甲医院人机与智能体协同环境系统(上.文章部分)
一、引言 1.1 研究背景与意义 1.1.1 三甲医院对高效协同系统的需求 三甲医院作为医疗体系的核心力量,承担着疑难病症诊治、医学科研教学等重要任务,其业务具有高度的复杂性。在日常运营中,三甲医院涉及多个科室,每个科室又包含众多专业领域,各科室之间需要紧密协作,共…...
对比DeepSeek、ChatGPT和Kimi的学术写作摘要能力
摘要 摘要是文章的精华,通常在200-250词左右。要包括研究的目的、方法、结果和结论。让AI工具作为某领域内资深的研究专家,编写摘要需要言简意赅,直接概括论文的核心,为读者提供快速了解的窗口。 下面我们使用DeepSeek、ChatGPT…...
「Unity3D」在Unity中使用C#控制显示Android的状态栏
Unity打包的Android默认都是全屏,如果想要在真机上显示状态栏,就需要额外设置,有两种方式: 第一种,使用Android的Java代码去控制,然后以插件的方式放到Unity中,被C#调用。第二种,使…...
Lua 环境的安装
1.安装Lua运行环境 本人采用的是在windows系统中使用cmd指令方式进行安装,安装指令如下: winget install "lua for windows" 也曾使用可执行程序安装过,但由于电脑是加密电脑,最后都已失败告终。使用此方式安装可以安…...
Pyside的QWebEngineProfile类
QWebEngineProfile 是 PySide/Qt 中用于管理浏览器引擎(WebEngine)配置的类,属于 QtWebEngineCore 模块。它主要用于控制网页的全局行为,例如缓存、Cookie、持久化存储、用户代理(User-Agent)、代理设置等。…...
java爬虫工具Jsoup学习
目录 前言 一、基本使用 二、爬取豆瓣电影的案例 三、Jsoup能做什么? 四、Jsoup相关概念 五、Jsoup获取文档 六、定位选择元素 七、获取数据 八、具体案例 前言 JSoup是一个用于处理HTML的Java库,它提供了一个非常方便类似于使用DOM࿰…...
基于SpringBoot电脑组装系统平台系统功能实现六
一、前言介绍: 1.1 项目摘要 随着科技的进步,计算机硬件技术日新月异,包括处理器(CPU)、主板、内存、显卡等关键部件的性能不断提升,为电脑组装提供了更多的选择和可能性。不同的硬件组合可以构建出不同类…...
Java实战项目-基于 springboot 的校园选课小程序(附源码,部署,文档)
Java 基于 springboot 的校园选课小程序 博主介绍:✌程序员徐师兄、8年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战*✌ 🍅文末获取源码联系🍅 👇&…...
洛谷P3884 [JLOI2009] 二叉树问题(详解)c++
题目链接:P3884 [JLOI2009] 二叉树问题 - 洛谷 | 计算机科学教育新生态 1.题目解析 1:从8走向6的最短路径,向根节点就是向上走,从8到1会经过三条边,向叶节点就是向下走,从1走到6需要经过两条边,…...
SQL99之内连接查询
SQL99是SQL语言的一个标准,于1999年发布。内连接查询是SQL中非常常用的一种查询方式,用于根据指定的条件从两个或多个表中获取相关联的数据。下面将详细介绍SQL99中的内连接查询,并以通熟易懂的语言进行讲解,同时给出代码例子、注…...
Qt Ribbon使用实例
采用SARibbon创建简单的ribbon界面 实例代码如下所示: 1、头文件: #pragma once #include <SARibbonBar.h> #include "SARibbonMainWindow.h" class QTextEdit; class SAProjectDemo1 : public SARibbonMainWindow { Q_OBJECT pub…...
【事务管理】
目录 一. 介绍与操作二. Spring事务管理三. 事务四大特性 \quad 一. 介绍与操作 \quad \quad 二. Spring事务管理 \quad 推荐加在经常进行增删改的方法上 \quad 三. 事务四大特性 \quad ctrlaltt...
[250129] Archinstall 3.0.2 发布 | Wolfram 语言与 Mathematica 14.2 版本发布
目录 Archinstall 3.0.2 版本发布Wolfram 语言与 Mathematica 14.2 版本发布🌟 主要亮点 Archinstall 3.0.2 版本发布 Archlinux 的自动化安装程序 Archinstall 发布了 3.0.2 版本,该版本带来了大量的改进和修复,以及一些新功能和贡献者。 …...
以创新芯片技术助力科技发展
在当今数字化与智能化浪潮中,芯片作为现代科技的核心,正悄然推动着各个行业的变革。厦门国科安芯科技有限公司专注于高性能芯片的研发与创新,致力于为工业、汽车和商业航天等领域提供高效、可靠的解决方案。以下是国科安芯推出的几款具有代表…...
单细胞-第五节 多样本数据分析,打分R包AUCell
文件在单细胞\5_GC_py\1_single_cell\3.AUCell.Rmd 1.基因 rm(list = ls()) load("g.Rdata")2.AUCell https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9897923 IF: NA NA NA用这个文章里的方法,将单细胞亚群的marker基因与ros相关基因取交集,用作AUCell的基因集…...
详解:网站地图对快速收录的重要性
本文来自:百万收录网 原文链接:https://www.baiwanshoulu.com/16.html 网站地图(Sitemap)在快速收录方面扮演着至关重要的角色。以下是对网站地图重要性的详细解析: 一、定义与功能 网站地图是一个包含网站上所有或…...
