当前位置: 首页 > news >正文

数据结构——单链表实现和注释浅解

关于单链表的基础部分增删查改的实现和一点理解,写在注释里~ 


 


 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);//申请节点
SLTNode* SLTBuyNode(SLTDataType x);//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//尾删
void SLTPopBack(SLTNode** pphead);
//头删
void SLTPopFront(SLTNode** pphead);//查找
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 SListDesTroy(SLTNode** pphead);


  SList.c

#include"SList.h"//只要形参变了而实参没有变化,那么就什么传的是值,而不是地址//data:节点存储的数据
//next:指向下一个节点的指针//打印
void SLTPrint(SLTNode* phead)
{//创建一个临时变量pcur将头节点的值赋予给pcur//pcur指向当前节点的值SLTNode* pcur = phead;//判断pcur是否为空while (pcur){//打印指向当前节点存储的数据printf("%d->", pcur->data);//将pucr指向的下一个节点指针的地址赋予给pcurpcur = pcur->next;}//当pcur为空时则打印NULLprintf("NULL\n");
}//申请节点
SLTNode* SLTBuyNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;return newnode;
}//尾插
// 只要形参变了而实参没有变化,那么就什么传的是值,而不是地址
//要先找到尾节点,再把尾节点的next指针指向新节点(newnode)
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);//*pphead 就是指向第一个节点的指针//申请一个新节点SLTNode* newnode = SLTBuyNode(x);//如果为空链表if (*pphead == NULL){*pphead = newnode;}else//非空链表{//找尾节点//定义一个尾节点,链表刚开始头节点和尾节点在同一个位置SLTNode* ptail = *pphead;//*pphead一级指针,指向第一个节点的指针//判断当尾节点指针指向的下一个位置为NULL结束//当ptail指针指向的下一个位置不为NULL时,ptail继续运行while (ptail->next){//把ptail指针指向的下一个位置的指针地址赋予ptailptail = ptail->next;}//当ptail指针指向的下一个位置为NULL时,ptail指向的就是尾结点//将ptail的next指针指向新节点ptail->next = newnode;}}//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);//申请一个新节点SLTNode* newnode = SLTBuyNode(x);//*pphead一级指针,指向第一个节点的指针//将新节点的next指针指向*pphead (头节点)newnode->next = *pphead;//然后再把新节点变成新的头节点*pphead*pphead = newnode;
}//尾删
void SLTPopBack(SLTNode** pphead)
{//链表不能为空assert(pphead && *pphead);//如果链表只有一个节点if ((*pphead)->next == NULL) // -> 优先级高于*{free(*pphead);*pphead = NULL;}else//如果链表有多个节点{//定义一个函数prev(前一个)//将prev和ptail都指向头节点 *ppheadSLTNode* prev = *pphead;SLTNode* ptail = *pphead;//判断ptail的next指针是否为空while (ptail->next){//将prev指向ptail的位置,ptail指向ptail的next指针的位置prev = ptail;ptail = ptail->next;}//如果ptail的next指针不为空,则把ptail free掉free(ptail);//将ptail和prev的next指针置为空ptail = NULL;prev->next = NULL;}
}//头删
void SLTPopFront(SLTNode** pphead)
{//链表不能为空assert(pphead && *pphead);//定义一个next指针,将头节点的next指针指向第二个节点(next)//用来保存第二个节点的位置SLTNode* next = (*pphead)->next;//释放头节点free(*pphead);//将第二个节点变成新的头节点*pphead = next;
}//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{//定义一个指针pcur指向头节点//这里不论pcur怎么变化都不会影响pheadSLTNode* pcur = phead;//while循环遍历while (pcur){//判断当前节点存储的数据是否与要查找的值相同if (pcur->data == x){//如果是就返回pcurreturn pcur;}//不是pcur就指向pcur的next指针继续走pcur = pcur->next;}//如果结束循环还没有找到就返回NULLreturn NULL;
}//在指定位置之  前  插入数据  prev:上一个
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{//链表不能为空assert(pphead && *pphead);assert(pos);//插入之前要先申请新节点SLTNode* newnode = SLTBuyNode(x);若pos == *pphead;说明是头插if (pos == *pphead){SLTPushFront(pphead, x);}else//不是头插{//先找到pos的前一个节点//定义一个函数prev,指向头节点SLTNode* prev = *pphead;//如果prev的下一个指针指向的  不是  pos则进行循环while (prev->next != pos){//不是prev就指向prev的next指针继续走prev = prev->data;}//找到之后//prev->newnode->pos//先将newnode的next指针指向pos,再把prev的next指针指向指向newnodenewnode->next = pos;prev->next = newnode;}}//在指定位置之  后  插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);//pos -> newnode -> pos->next//先将newnode的next指针指向pos的下一个节点(next),再把pos的next指针指向newnodenewnode->next = pos->next;pos->next = newnode;
}//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);//pos是头结点if (pos == *pphead){//头删SLTPopFront(pphead);}else//pos不是头结点{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//prev pos pos->next//要先把prev的下一个指针指向pos的下一个指针指向的位置再释放掉pos// 防止找不到pos的下一个指针指向的位置prev->next = pos->next;free(pos);pos = NULL;}
}//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);//定义一个临时指针del,将pos的next指针存放到del中SLTNode* del = pos->next;//把pos的next指针指向del的next指针//pos del del->nextpos->next = del->next;free(del);del = NULL;
}//销毁链表
void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}//pcur*pphead = NULL;
}


Test.c 

#include"SList.h"void SListTest01()
{//链表是由一个一个的节点组成//创建几个节点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);
}void SListTest02()
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPrint(plist); // 1->2->3->4->NULLSListDesTroy(&plist);SLTPrint(plist);//测试查找//SLTNode* find = SLTFind(plist, 1);//SLTInsert(&plist, find, 11);//SLTInsertAfter(find, 11);//删除pos节点//SLTErase(&plist, find);//SLTEraseAfter(find);//SLTPrint(plist);//if (find == NULL)//{//	printf("没有找到!\n");//}//else {//	printf("找到了!\n");//}//SLTPushBack(NULL, 5);////测试头插//SLTPushFront(&plist, 6);//SLTPrint(plist);//SLTPushFront(&plist, 7);//SLTPrint(plist);//SLTPushFront(&plist, 8);//SLTPrint(plist);//测试头删//SLTPopFront(&plist);//SLTPrint(plist);// 2->3->4->NULL//SLTPopFront(&plist);//SLTPrint(plist);//SLTPopFront(&plist);//SLTPrint(plist);//SLTPopFront(&plist);//SLTPrint(plist);//SLTPopFront(&plist);//SLTPrint(plist);}int main()
{//SListTest01();SListTest02();return 0;
}

 


一点浅解,感谢观看~

相关文章:

数据结构——单链表实现和注释浅解

关于单链表的基础部分增删查改的实现和一点理解&#xff0c;写在注释里~ SList.h #pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h>//定义节点的结构 //数据 指向下一个节点的指针 typedef int SLTDataType;typedef struct SListNo…...

滑动窗口系列(同向双指针)/9.7

新的解题思路 一、三数之和的多种可能 给定一个整数数组 arr &#xff0c;以及一个整数 target 作为目标值&#xff0c;返回满足 i < j < k 且 arr[i] arr[j] arr[k] target 的元组 i, j, k 的数量。 由于结果会非常大&#xff0c;请返回 109 7 的模。 输入&…...

C# 窗体中Control以及Invalidate,Update,Refresh三种重绘方法的区别

在 C# 中&#xff0c;Control 类是 Windows Forms 应用程序中所有控件的基类。它提供了控件的基本功能和属性&#xff0c;这些功能和属性被所有继承自 Control 类的子类所共享。这意味着 Control 类是构建 Windows Forms 应用程序中用户界面元素的基础。 以下是 Control 类的一…...

缓存类型以及读写策略

缓存&#xff08;Cache&#xff09;是一种高效的数据存储技术&#xff0c;旨在提高数据访问速度。 它将频繁访问或最近使用的数据临时存储在更快速但较小的存储介质&#xff08;如内存&#xff09;中&#xff0c;以减少从较慢的存储设备&#xff08;如硬盘或远程服务器&#x…...

自动驾驶---Motion Planning之轨迹拼接

1 背景 笔者在之前的专栏中已经详细讲解了自动驾驶Planning模块的内容&#xff1a;包括行车的Behavior Planning和Motion Planning&#xff0c;以及低速记忆泊车的Planning。 本篇博客主要聊一聊Motion Planning中轨迹拼接的相关内容。从网络上各大品牌的车主拍摄的智驾视频来看…...

没资料的屏幕怎么点亮?思路分享

这次尝试调通一个没资料的屏幕&#xff0c;型号是HYT13264&#xff0c;这个是淘宝上面的老王2.9元屏&#xff0c;成色很好但是长期库存没有资料和代码能点亮&#xff0c;仅仅只有一个引脚定义。这里我使用Arduino Nano作为控制器尝试点亮这个模块。 首先&#xff0c;已知别人找…...

通信工程学习:什么是FEC前向纠错

FEC&#xff1a;前向纠错 FEC&#xff08;Forward Error Correction&#xff0c;前向纠错&#xff09;是一种增加数据通信可信度的技术&#xff0c;广泛应用于计算机网络、无线通信、卫星通信等多种数据传输场景中。其基本原理和特点可以归纳如下&#xff1a; 一、FEC前向纠错…...

【机器人工具箱Robotics Toolbox开发笔记(二十)】机器人工具箱SerialLink I类函数参数说明

机器人工具箱中的SerialLink表示串联机器人型机器人的具体类。该类使用D-H参数描述,每个关节一组。SerialLink I类包含的参数如表1所示。 表1 SerialLink I类参数 参 数 意 义 参 数 意 义 plot 显示机器人的图形表示 jacobn 工具坐标系中的雅可比矩阵 plot3D 显示机…...

单调栈的实现

这是C算法基础-数据结构专栏的第二十四篇文章&#xff0c;专栏详情请见此处。 引入 单调栈就是满足单调性的栈结构&#xff0c;它最经典的应用就是给定一个序列&#xff0c;找出每个数左边离它最近的比它大/小的数。 下面我们就来讲单调栈的实现。 定义 单调栈就是满足单调性…...

ffmpeg的安装和使用教程

在Linux上安装和使用FFmpeg可以方便地完成音视频的编码、解码、转码等操作。以下是详细的安装和使用教程。 安装FFmpeg FFmpeg的安装方法会因为不同的Linux发行版有所不同。下面是几种常见的安装方法&#xff1a; Ubuntu/Debian 打开终端&#xff0c;更新包列表并安装FFmpe…...

从计组中从重温C中浮点数表示及C程序翻译过程

目录 移码​编辑 传统浮点表示格式 浮点数的存储&#xff08;ieee 754&#xff09;->修炼内功 例子&#xff1a; ​编辑 浮点数取的过程 C程序翻译过程 移码 传统浮点表示格式 浮点数的存储&#xff08;ieee 754&#xff09;->修炼内功 根据国际标准IEEE&#xff0…...

MySQL常用函数(总结)详细版

1. 字符串函数 CONCAT(str1, str2, ...)&#xff1a;将多个字符串连接成一个字符串。 SELECT CONCAT(Hello, , World); LENGTH(str)&#xff1a;返回字符串的长度&#xff08;字节数&#xff09;。 SELECT LENGTH(Hello); SUBSTRING(str, pos, len)&#xff1a;从字符串 …...

学习记录——day41 C++ 类的静态成员 static

静态成员&#xff0c;是类中不依赖于类对象而独立存在的成员变量&#xff0c;但仍然属于类&#xff0c;是成员的一种 静态成员的空间分配发生在出现编译阶段&#xff0c;不占用类的空间 静态成员分为&#xff0c;静态成员变量和静态成员函数 静态成员变量 1、相关概念 1&…...

JVM - Java内存区域

文章目录 目录 文章目录 运行时数据区域 程序计数器 栈 Java虚拟机栈 本地方法栈 栈帧的组成 局部变量表 操作数栈 帧数据 堆 方法区 直接内存 总结 运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存区域划分为若干个不同的数据区域。这些区…...

本地电脑交叉编译ffmpeg 到 windows on arm64

本地电脑交叉编译ffmpeg 到 windows on arm64 我这里有编译好的win on arm 的 ffmpeg : https://github.com/wmx-github/ffmpeg-wos-arm64-build 使用 llvm-mingw 工具链 https://github.com/mstorsjo/llvm-mingw/releases 前缀 aarch64-w64-mingw32- 这个库是ubuntu 交叉编译…...

使用 @NotEmpty、@NotBlank、@NotNull 注解进行参数校验

使用 NotEmpty、NotBlank、NotNull 注解进行参数校验 一、前言二、依赖三、使用 NotEmpty、NotBlank、NotNull 注解进行参数校验1. NotNull2. NotEmpty3. NotBlank4. 区别与适用场景 四、实践中的应用五、总结 一、前言 在 Java 开发中&#xff0c;参数校验是确保数据一致性和…...

关于Qt在子线程中使用通讯时发生无法接收数据的情况

在多线程应用中&#xff0c;串口通讯或TCP通讯的场景常常涉及到持续的读写操作&#xff0c;如果子线程处理不当&#xff0c;可能会导致信号阻塞问题。本文将通过串口通讯或TCP通讯为例&#xff0c;详细解释如何在多线程环境中避免信号阻塞&#xff0c;并提供代码示例。 1. 问题…...

HTML:从历史演进到未来创新的网页基石

该论文为AI生成&#xff0c;请勿运用到正式的论文上&#xff0c;以下仅供参考 一、引言 1.1 研究背景 HTML&#xff08;Hypertext Markup Language&#xff09;作为网页构建的基础语言&#xff0c;在互联网的发展历程中占据着至关重要的地位。自 1993 年诞生以来&#xff0c…...

向量的叉积、点积、外积

向量的叉积、点积和外积是向量代数中非常重要的操作,用于描述向量间的关系。它们广泛应用于物理、计算机图形学、几何以及蛋白质结构分析等领域。下面对每个运算进行详细介绍,并通过 PyTorch 示例代码展示其实现。 1. 点积 (Dot Product) 点积是两个向量之间的数量积,结果…...

UNI-APP 溢出隐藏显示省略号

✍经常在项目里面使用到&#xff0c;又没有记住懒得找了&#xff0c;故此写一篇记录一下! CSS单行显示省略号 /* CSS样式 */ .ellipsis {overflow: hidden; /* 隐藏超出的内容 */text-overflow: ellipsis; /* 显示省略号 */white-space: nowrap; /* 不换行 */ } CS…...

DeepSeek代码质量评估实战手册:7步完成从混沌到可度量的质变跃迁

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;DeepSeek代码质量评估的底层逻辑与核心价值 DeepSeek代码质量评估并非简单地统计行数或检测语法错误&#xff0c;而是基于多维语义理解构建的推理系统。其底层逻辑融合了静态分析、符号执行与大语言模型生成式…...

基于2D工程图几何特征与梯度提升模型的制造成本智能预测

1. 项目概述&#xff1a;从图纸到报价的智能革命在制造业&#xff0c;尤其是像汽车零部件这样的离散制造领域&#xff0c;报价速度直接决定了订单的生死。传统上&#xff0c;拿到一张新的2D工程图&#xff08;DWG格式&#xff09;&#xff0c;成本工程师需要花上几天甚至几周时…...

UE4动画蓝图实战:用双骨骼IK节点搞定手部穿模,附完整蓝图节点截图

UE4动画蓝图实战&#xff1a;双骨骼IK节点解决手部穿模的完整指南在角色动画开发中&#xff0c;手部穿模问题堪称"视觉杀手"。想象一下精心设计的角色挥拳时&#xff0c;拳头直接穿过墙壁或敌人身体——这种违和感足以毁掉整个场景的沉浸感。本文将彻底解决这个痛点&…...

从入门到上岗,Java+AI 复合型人才养成攻略

当下编程行业格局正在悄然改变,纯 Java 后端岗位内卷日趋严重,薪资增长逐步放缓;纯粹的 AI 算法岗门槛居高不下,对学历、数理功底要求严苛,普通开发者很难入局。 而Java+AI 复合型开发顺势成为行业刚需岗位,既依托成熟的 Java 体系承接业务开发,又能融入人工智能技术实…...

新手村任务:成为一个架构师需要哪些装备?

新手村任务:成为一个架构师需要哪些装备? 一、前言 如果你刚入行不久,想成为一名架构师,那这篇文章就是为你写的。 我们把成为架构师比作一个RPG游戏,你是主角,需要收集各种装备、刷经验、升级技能。 新手村的第一个任务就是:了解你需要哪些装备。 二、架构师技能树…...

对比 Token Plan 与按量计费在 Taotoken 平台上的成本体感差异

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 对比 Token Plan 与按量计费在 Taotoken 平台上的成本体感差异 对于个人开发者或项目管理者而言&#xff0c;在接入大模型服务时&a…...

中兴光猫终极管理指南:解锁工厂模式与Telnet权限的实战教程

中兴光猫终极管理指南&#xff1a;解锁工厂模式与Telnet权限的实战教程 【免费下载链接】zteOnu A tool that can open ZTE onu device factory mode 项目地址: https://gitcode.com/gh_mirrors/zt/zteOnu 掌握中兴光猫的设备管理和权限获取能力是网络管理员和技术爱好者…...

关联规则挖掘在Calabi-Yau流形Hodge数分析中的应用与复现

1. 项目概述&#xff1a;当数据挖掘遇见高维几何在理论物理和代数几何的交叉领域&#xff0c;Calabi-Yau流形一直扮演着核心角色。这些具有特殊拓扑结构的空间&#xff0c;不仅是弦理论中额外维度紧化的关键候选者&#xff0c;其本身丰富的数学性质也吸引着无数研究者。然而&am…...

武汉国电华美串联谐振试验装置,现场用着心里有底

在高压试验现场干了这么多年&#xff0c;这位老师傅常说&#xff0c;一台好的串联谐振装置&#xff0c;就是试验人员的胆。面对GIS、大型变压器、超高压电缆这些大电容试品&#xff0c;没有趁手的谐振设备&#xff0c;交流耐压试验根本没法干。16875kVA/225kV这个规格&#xff…...

Jupyter Notebook里跑argparse脚本总报错?一个空列表参数搞定ipykernel_launcher.py error

Jupyter Notebook中argparse报错的终极解决方案&#xff1a;空列表参数实战解析在数据科学和机器学习的工作流中&#xff0c;Jupyter Notebook因其交互式特性成为众多研究者的首选工具。然而&#xff0c;当我们尝试在Notebook中运行那些原本为命令行设计的Python脚本时&#xf…...