数据结构与算法系列之单链表

💗 💗 博客:小怡同学
💗 💗 个人简介:编程小萌新
💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞
这里写目录标题
- test.h
- SList.h
- 注意事项
- 一级指针与二级指针的使用
- assert的使用
- 空链表与顺序表的区别及优缺点
- 详解各接口函数的功能
test.h
#include "SList.h"
void Test()
{SLTNode* plist = NULL;SLPrint(plist);SLPushBack(&plist, 7);SLPushBack(&plist, 8);SLPushBack(&plist, 9);SLPushBack(&plist, 10);SLPrint(plist);//SLTNode* ret = SListFind(plist, 8);//SLPrint(plist);//SLisTEraseAfter(ret);//SLPrint(plist);//SListInsert(&plist, ret, 3);//SListInsertAfter(ret, 4);//SlistErase(&plist , ret);//SLisTEraseAfter(ret);//SLPrint(plist);
}int main()
{Test();
}
SList.h
```c
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;struct SList* next;
}SLTNode;void SLPrint(SLTNode* phead);//打印
void SLPushBack(SLTNode** pphead, SLTDataType x);//尾插
void SLTPushFront(SLTNode** pphead, SLTDataType x);//头插
void SLTPopBack(SLTNode** pphead);//尾删
void SLTPopFront(SLTNode** pphead);//头删
SLTNode* BuySLTode(SLTDataType x);//开辟一个节点
SLTNode* SListFind(SLTNode* phead, SLTDataType x);//找到x这个节点
void SListInsert(SLTNode** phead, SLTNode* pos, SLTDataType x);//在pos之前增加data为x这个节点
void SListInsertAfter(SLTNode* pos, SLTDataType x);//在pos之后增加data为x这个节点
void SlistErase(SLTNode** pphead, SLTNode* pos);//删除在pos之前,删除这个节点
void SLisTEraseAfter(SLTNode* pos);//删除pos之后的节点
# SList.c```c
#include "SList.h"
SLTNode* BuySLTode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = x;newnode->next = NULL;return newnode;
}void SLPrint(SLTNode* phead)
{SLTNode* cur = phead;while (cur != NULL){printf("%d->",cur->data);cur = cur->next;}printf("NULL\n");
}void SLPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTode(x);if (*pphead == NULL){*pphead = newnode;}else{SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail ->next= newnode;}
}void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySLTode(x);if (*pphead == NULL){*pphead = newnode;}else{newnode->next = *pphead;*pphead = newnode;}
}void SLTPopBack(SLTNode** pphead)
{assert(pphead);assert(*pphead);if ( (*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLTNode* tail = *pphead;SLTNode* prev = NULL;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;}
}void SLTPopFront(SLTNode** pphead)
{assert(pphead);assert(*pphead);SLTNode* cur = *pphead;*pphead = (*pphead)->next;free(cur);cur = NULL;}SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{SLTNode* cur = phead;while (cur){if (cur->data == x)return cur;cur = cur->next;}return NULL;
}void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);if (*pphead == pos){SLTPushFront(pphead, x);}else{SLTNode* cur = pphead;while (cur->next != pos){cur = cur->next;}SLTNode* newnode = BuySLTode(x);cur->next = newnode;newnode->next = pos;}}void SListInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySLTode(x);newnode->next = pos->next;pos->next = newnode;
}void SlistErase(SLTNode**pphead, SLTNode* pos)
{assert(pphead);assert(pos);//assert(*pphead);if (*pphead == pos){SLTPopFront(pphead);}else{SLTNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}cur->next= pos->next;free(pos);}}void SLisTEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* cur = pos->next;pos->next = pos->next->next;free(cur);cur = NULL;
}
注意事项
一级指针与二级指针的使用
可以看得出来,接口函数传参时有的需要而二级指针,有的需要一级指针
总结为一句话,改变结构体地址需要二级指针,改变结构体(SLTNode)成员需要一级指针。
解析如下
1.根据c语言,实参传址调用与传值调用知识我们可以知道,改变元素大小需要传入地址。而改变地址,则需要传入地址的地址。因为形参只是实参的拷贝 函数销毁之后形参将不存在

2.改变结构体的地址,具体是如何改变呢
通过头指针的地址(pphead这个是二级指针),再解引用得到头指针(headnoe),就可以使用且改变了。

3.通过结构体(headnode),headnode->next可以得到下一个结构体node1
assert的使用
从SList.c可以看出 有时assert(pphead(二级指针)),有时assert(*pphead(一级指针)),
1.当有二级指针传入时,必须使用assert(pphead)断言因为 pphead是头指针的地址 ,虽然头指针 为NULL但是,头指针的地址是真实存在的(也就是地址中的地址)。
2.assert(*pphead)是当链表中已经没有节点存在了,不能进行删除结点的行为。

空链表与顺序表的区别及优缺点
区别
1.顺序表为空时 因为结构体不为NULL,只是 size ==0 链表 phead 为空时,没有节点则头指针为NULL。
2,为什么链表不能和顺序表一样直接size++就可以存入数据呢
因为链表每个节点的地址位置都是malloc函数开辟,每个起点位置可能都不一样。而顺序表相当是开辟一段连续内存空间。
优缺点
一.顺序表存储
优点:顺序表存储是将数据元素放到一块连续的内存存储空间,通过下标 访问高效,直接存储与删除
缺点:1.插入和删除比较慢,需要移动大量元素,
2.开辟空间是不可减少的,不可以动态增加长度,容易造成内存浪费
二 .链表存储
原理:没有空间限制,不会溢出,节省空间内存
优点:插入和删除速度快,只需要改变指针指向即可
缺点:不可通过下标访问,需要遍历节点
详解各接口函数的功能
void SLPrint(SLTNode* phead)
void SLPrint(SLTNode* phead)
{
//不改变结构体地址,只是循环打印数据所以传一级指针SLTNode* cur = phead;while (cur != NULL){printf("%d->",cur->data);cur = cur->next;}printf("NULL\n");
}
void SLPushBack(SLTNode** pphead, SLTDataType x)
assert(pphead);//因为二级指针,肯定存在,所以需要断言SLTNode* newnode = BuySLTode(x);//判断第一个节点是否为空,改变头节点if (*pphead == NULL){*pphead = newnode;}else{SLTNode* tail = *pphead;while (tail->next != NULL)//寻找最后一个元素{tail = tail->next;}tail ->next= newnode;//在最后的元素添加节点}
void SLTPushFront(SLTNode** pphead, SLTDataType x)
assert(pphead);//因为头插改变了头节点,所以传二级指针SLTNode* newnode = BuySLTode(x);//当没有节点时,增加节点if (*pphead == NULL){*pphead = newnode;}else{newnode->next = *pphead;//增加首节点*pphead = newnode;}
void SLTPopBack(SLTNode** pphead)
assert(pphead);//二级指针必须断言assert(*pphead);//因为当头节点为空时,不能删除//当只有一个节点时,释放头节点的空间if ( (*pphead)->next == NULL){free(*pphead);*pphead = NULL;}//当有两个或两个以上的节点时else{SLTNode* tail = *pphead;SLTNode* prev = NULL;while (tail->next != NULL)//找到最后一个元素,以及倒数第二个,所以定义了两个指针,因为只找到最后一个并释放后需要把倒数第二个节点(的next)设为NULL{prev = tail;tail = tail->next;}free(tail);tail = NULL;prev->next = NULL;}
void SLTPopFront(SLTNode** pphead)
assert(pphead);//二级指针必定不为空assert(*pphead);//因为链表必须有节点才可以删除,所以需要断言SLTNode* cur = *pphead;*pphead = (*pphead)->next;free(cur);cur = NULL;
SLTNode* BuySLTode(SLTDataType x)
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//开辟一个新节点if (newnode == NULL){perror("malloc fail");return NULL;}//初始化newnode->data = x;newnode->next = NULL;return newnode;
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
SLTNode* cur = phead;while (cur){if (cur->data == x)return cur;//找到返回此节点坐标cur = cur->next;}return NULL;//找不到返回NULL
void SListInsert(SLTNode** phead, SLTNode* pos, SLTDataType x)
assert(pphead);//二级指针必不为空assert(pos);//判断pos是否为有效地址//判断头节点是否可以插入if (*pphead == pos){SLTPushFront(pphead, x);}else{SLTNode* cur = pphead;while (cur->next != pos)//找到pos之前的位置{cur = cur->next;}SLTNode* newnode = BuySLTode(x);cur->next = newnode;//链接新的节点newnode->next = pos;}
void SListInsertAfter(SLTNode* pos, SLTDataType x)
assert(pos);//判断pos位置SLTNode* newnode = BuySLTode(x);//链接新的节点newnode->next = pos->next;pos->next = newnode;
void SlistErase(SLTNode** pphead, SLTNode* pos)
assert(pphead);//二级指针必不为空assert(pos);//pos位置是否合理assert(*pphead);/删除一个节点,所以链表必不为空//改变了头指针,地址改变需要二级指针if (*pphead == pos){SLTPopFront(pphead);}else{SLTNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}cur->next= pos->next;free(pos);}
void SLisTEraseAfter(SLTNode* pos)
assert(pos);//判断pos位置是否合理assert(pos->next);//因为要删除pos的下一个位置的节点,所以只有一个节点不能删除SLTNode* cur = pos->next;pos->next = pos->next->next;free(cur);cur = NULL;

相关文章:
数据结构与算法系列之单链表
💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 这里写目录标题test.hSList.h注意事项一级指针与二级指针的使用assert的使用空…...
MySQL基础
本单元目标 一、为什么要学习数据库 二、数据库的相关概念 DBMS、DB、SQL 三、数据库存储数据的特点 四、初始MySQL MySQL产品的介绍 MySQL产品的安装 ★ MySQL服务的启动和停止 ★ MySQL服务的登录和退出 ★ MySQL的常见命令和语法规范 五、…...
面试热点题:环形链表及环形链表寻找环入口结点问题
环形链表 问题: 给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接…...
【算法】DFS与BFS
作者:指针不指南吗 专栏:算法篇 🐾题目的模拟很重要!!🐾 文章目录1.区别2.DFS2.1 排列数字2.2 n-皇后问题3.BFS3.1走迷宫1.区别 搜索类型数据结构空间用途过程DFSstackO( n )不能用于最短路搜索到最深处&a…...
湖州银行冲刺A股上市:计划募资约24亿元,资产质量水平较高
3月4日,湖州银行股份有限公司(下称“湖州银行”)递交招股书,准备在上海证券交易所主板上市。本次冲刺上市,湖州银行计划募资23.98亿元,将在扣除发行费用后全部用于补充该行资本金。 湖州银行在招股书中表示…...
高性能网络I/O框架-netmap源码分析
前几天听一个朋友提到这个netmap,看了它的介绍和设计,确实是个好东西。其设计思想与业界不谋而合——因为为了提高性能,几个性能瓶颈放在那里,解决方法自然也是类似的。 netmap的出现,它既实现了一个高性能的网络I/O框…...
SpringBoot监听机制-以及使用
11-SpringBoot事件监听 Java中的事件监听机制定义了以下几个角色: ①事件:Event,继承 java.util.EventObject 类的对象 ②事件源:Source ,任意对象Object ③监听器:Listener,实现 java.util…...
若依学习——定时任务代码逻辑 详细梳理(springboot整合Quartz)
springboot整合Quartz关于若依定时任务的使用可以去看视频默认定时任务的使用关于springboot整合quartz的整合参考(150条消息) 定时任务框架Quartz-(一)Quartz入门与Demo搭建_quarzt_是Guava不是瓜娃的博客-CSDN博客(150条消息) SpringBoot整合Quartz_springboot quartz_桐花思…...
C++---最长上升子序列模型---拦截导弹(每日一道算法2023.3.4)
注意事项: 本题为"线性dp—最长上升子序列的长度"的扩展题,这里只讲贪心思路,dp去这个看。 题目: 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷:虽然它…...
【机器学习面试】百面机器学习笔记和问题总结+扩展面试题
第1章 特征工程 1、为什么需要对数值类型的特征做归一化? (1)消除量纲,将所有特征统一到一个大致相同的区间范围,使不同指标之间具由可比性; (2)可以加快梯度下降收敛的速度&#…...
【2021.12.28】ctf逆向中的迷宫问题(含exe及wp)
【2021.12.28】ctf逆向中的迷宫问题(含exe及wp) 文章目录【2021.12.28】ctf逆向中的迷宫问题(含exe及wp)1、迷宫简介(1)简单例子(2)一般的迷宫代码2、二维迷宫(1…...
WSL2使用Nvidia-Docker实现深度学习环境自由部署
1. Win11 显卡驱动的安装 注意:WSL2中是不需要且不能安装任何显卡驱动的,它的显卡驱动完全依赖于 Win11 中的显卡驱动,因此我们只需要安装你显卡对应的 Win11 版本显卡驱动版本(必须是 Win11 版本的驱动),…...
SpringBoot入门 - 配置热部署devtools工具
在SpringBoot开发调试中,如果我每行代码的修改都需要重启启动再调试,可能比较费时间;SpringBoot团队针对此问题提供了spring-boot-devtools(简称devtools)插件,它试图提升开发调试的效率。准备知识点什么是…...
CANFDNET-200U-UDP配置与数据收发控制
一、启动ZCANPRP,打开设备管理页面,选择类型CANFDNET-200U-UDP,如图1 图1 二、打开设备,启动,在相应页面如图2,配置协议,CANFD 加速,本地端口,IP地址,工作端口。 图2 三、发送相应数…...
嵌入式中backtrace的使用
大家好,我是bug菌~ backtrace主要用于调试程序时,能够打印出程序在运行过程中的函数调用栈,以帮助开发者快速定位程序出现异常或崩溃的原因。 通过backtrace的输出,开发者可以了解程序在哪个函数出现问题,…...
CV学习笔记-Faster-RCNN
Faster R-CNN 文章目录Faster R-CNN1. 目标检测算法1.1 计算机视觉有五大应用1.2 目标检测任务1.3 目标检测算法概述2. 边框回归(Bounding-Box regression)2.1 IoU2.2 统计学中的指标2.3 边框回归3. Faster-RCNN网络3.1 Conv layers3.2 Region Proposal …...
大型三甲医院云HIS系统源码 强大的电子病历+完整文档
医院HIS系统源码云HIS系统:SaaS运维平台多医院入驻强大的电子病历完整文档 有源码,有演示 一、系统概述 采用主流成熟技术,软件结构简洁、代码规范易阅读,SaaS应用,全浏览器访问前后端分离,多服务协同&am…...
如何使用Spring Cloud搭建高可用的Elasticsearch集群?详解Elasticsearch的安装与配置及Spring Boot集成的实现
Spring Cloud 是一个基于 Spring Boot 的微服务框架,它提供了一系列组件和工具,方便开发人员快速搭建和管理分布式系统。Elasticsearch 是一个开源的全文搜索引擎,也是一个分布式、高可用的 NoSQL 数据库。本篇博客将详细讲解如何使用 Spring…...
phpinfo包含临时文件Getshell全过程及源码
目录 前言 原理 漏洞复现 靶场环境 源码 复现过程 前言 PHP LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件,例如session文件、日志文件、临时文件等。但是,只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。假如在服…...
ubuntu22.04 Desktop 服务器安装
操作系统 使用的是Uubntu22.04 Desktop的版本,系统安装后,默认开启了53端口和631端口 关闭udp 5353、53791端口(avahi-daemon服务) sudo systemctl stop avahi-daemon.socket avahi-daemon.service sudo systemctl disable ava…...
WPF进阶:Canvas动态图形绘制与交互实现
1. Canvas动态图形绘制基础 WPF中的Canvas就像一块无限延伸的画布,我们可以在这块画布上自由地绘制各种图形元素。与静态绘制不同,动态绘制的魅力在于图形能够根据用户操作实时变化。我刚开始接触Canvas时,最让我兴奋的就是看到鼠标移动时能实…...
FedoraWorkstation43安装中州韵(ibus-rime)输入法引擎+雾凇拼音+万象语言模型
1、安装ibus-rime sudo dnf install ibus-rime librime-devel librime-tools librime-lua2、使用东风破工具安装雾凇 cd ~/ git clone https://github.com/rime/plum.git plum cd plum bash rime-install iDvel/rime-ice:others/recipes/full # 更多参考 https://github.com/iD…...
自指宇宙学形式化验证套件 (Coq‑SRU v1.2.0)
自指宇宙学形式化验证套件 (Coq‑SRU v1.2.0)技术摘要 正式整编版 项目标识:Coq Formalization of Self‑Referential Universe (Coq‑SRU) 版本:v1.2.0(对齐《世毫九自指宇宙学》理论第三部分) 代码仓库:https://git…...
VS2022 + WinForms:从拖控件到写逻辑,手把手带你做出第一个C#计算器
VS2022 WinForms:从拖控件到写逻辑,手把手带你做出第一个C#计算器 第一次打开Visual Studio 2022时,那个闪亮的启动界面可能会让你既兴奋又不知所措。作为微软最新的集成开发环境,VS2022为C#开发者提供了强大的工具链࿰…...
Honey Select 2终极增强补丁:3分钟快速配置完整模组生态
Honey Select 2终极增强补丁:3分钟快速配置完整模组生态 【免费下载链接】HS2-HF_Patch Automatically translate, uncensor and update HoneySelect2! 项目地址: https://gitcode.com/gh_mirrors/hs/HS2-HF_Patch 你是否曾为《Honey Select 2》的模组安装繁…...
CentOS7下KingbaseES V9与MySQL性能对比实测:从安装到查询优化的全流程体验
CentOS7下KingbaseES V9与MySQL性能对比实测:从安装到查询优化的全流程体验 在国产数据库技术快速发展的今天,越来越多的企业开始关注从传统数据库向国产化解决方案的迁移。作为国产数据库中的佼佼者,KingbaseES V9凭借其出色的MySQL兼容性和…...
Jmeter接口测试项目实战
🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 1、什么是jmeter?JMeter是100%完全由Java语言编写的,免费的开源软件,是非常优秀的性能测试和接口测试工具,支持主流…...
如何高效使用猫抓cat-catch:5个关键技巧完全指南
如何高效使用猫抓cat-catch:5个关键技巧完全指南 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否经常遇到这样的情况:…...
保姆级教程:手把手教你用Zabbix监控MySQL数据库(Percona模板实战)
深度实战:基于Percona模板构建企业级MySQL监控体系 当数据库规模突破百万级QPS时,传统的手动检查方式就像用体温计测量森林大火——既低效又危险。去年某电商大促期间,我们曾因未及时发现连接数耗尽导致核心交易库雪崩,这个教训让…...
深入解析Triton Inference Server的Backend机制与实战配置
1. Triton Inference Server的Backend机制揭秘 第一次接触Triton Inference Server时,我被它的Backend机制搞得一头雾水。直到在真实项目中踩过几次坑后,才真正理解它的精妙之处。简单来说,Backend就像是一个万能适配器,让Triton能…...
