【数据结构和算法初阶(C语言)】链表-单链表(手撕详讲单链表增删查改)

目录
1.前言:顺序表回顾:
1.1顺序表的优缺点
2.主角----链表
2.1链表的概念
2.2定义一个单链表的具体实现代码方式
3.单链表对数据的管理----增删查改
3.1单链表的创建
3.2单链表的遍历实现
3.2.1利用遍历实现一个打印我们链表内容的函数的函数
3.3头插法----从头部插入数据实现
3.4尾插法---从尾部插入数据
3.5尾删法-----从尾部删除数据
3.6头删法
3.7寻找函数
3.8修改函数
3.9在pos位置前插入
3.10在pos位置后插入
3.11在pos位置前删除
3.12在pos位置后一个位置删除
3.13在pos位置删除
4.补充链表类型暂时了解
5.结语
1.前言:顺序表回顾:
顺序表知识回顾
1.1顺序表的优缺点
- 优点:
1.尾插、尾删速度足够快
2.可以使用下标来进行随机访问和数据修改
- 缺点:
1. 中间/头部的插入删除,时间复杂度为O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。比如我们realloc增添空间还会涉及到原始空间数据的拷贝和原始空间的释放。
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
为了解决单链表的这缺点,于是我们引入了链表,链表优点(可以按需申请空间)
2.主角----链表
(今天重要讲解单链表),链表具有八种结构
2.1链表的概念
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表 中的指针链接次序实现的 。就像火车:

2.2单链表的结构演示
在数据结构中,我们往往会以创建结构体的方式来实现链表,在结构体中定义至少定义两个成员:一个保存我们当前节点的数据,我们称为数据域,另外一个成员保存下一个节点的地址,我们称为指针域。

从上图,我们就可以发现,链式结构在逻辑上是连续的就是我们可以通过指针顺序找到链表中的每个节点但是,在物理上不一定连续,因为我们每一个节点的空间都是通过malloc在堆上申请开辟的空间,那么地址可能不连续。
2.2定义一个单链表的具体实现代码方式
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;//数据领域struct SListNode* next;//定义指针领域,方便保存下一个节点的地址}SLNode;
为了后期使用方便,我把整型这个类型重新定义了一下,后续如果需要改变我们这个程序中的数据类型,比如换成doubble类型,我们换一下宏定义就好。
![]()
3.单链表对数据的管理----增删查改
3.1单链表的创建
有了结构体类型,那我们就可以创建一个单链表:
1.首先我们先创建一个节点,由于后续插入等等操作都要创建节点,这里我们就可以将节点创建过程分装为一个函数:
SLNode* BuySListNode(SLTDataType x) {//首先为我们的节点申请空间,创建一个节点,就申请这个结构体类型那么大的一个空间就行SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));//判断一下是否开辟成功if (newnode == NULL){perror("malloc");exit(-1);}//开辟成功,就初始化这个节点newnode->data = x;newnode->next = NULL;return newnode;//返回节点地址 }2.然后我们将每个节点链接起来,通个指针和每个节点的地址,这里就涉及头部插入数据和尾部插入数据,我们放在下面实现:
3.2单链表的遍历实现

3.2.1利用遍历实现一个打印我们链表内容的函数的函数
void SLPrint(SLNode* phead) {SLNode* cur = phead;while (cur){printf("%d ->", cur->data);cur = cur->next;//指针移动到下一个节点}printf("NULL");}
3.3头插法----从头部插入数据实现
首先,我们先定义准备一个头指针,用于保存我们链表第一个节点的地址,,方便我们后期使用整块链表。
然后,当我们还没有链表,这时候放入第一个节点:
我们把节点地址给我们的头指针就好。
2.当我们的头指针不为空,这时要插入数据
应该将第一个节点的地址赋值给newnode的next,然后将我们newnode节点作为我们的心的头结点将地址给头指针。
两种情况可以视为一种情况,只是第一种特殊一下,我们的头指针指向空。
注意:在我们写头插函数的时候,传递的是头指针的地址,我们在函数中解引用操作操作的是原先的指针,这样才能整体使用我们的空间,如果我们只是传指针,那么在我们的头插函数中的头指针,只是我们真正头指针的一份拷贝,这样函数结束,形参就销毁,虽然空间开辟了,但是调用结束我们使用的还是原来没插入前的空间。
void SListPushBack(SLNode** phead,int x) {SLNode* newnode = BuySListNode(x);newnode->next = *phead;*phead = newnode;}
3.4尾插法---从尾部插入数据
当我们还没有链表,这时候放入第一个节点:
两种情况实现:
void SLTPushBack(SLNode** phead, SLTDataType x) {SLNode* newnode = BuySListNode(x);//创建新节点if (*phead == NULL){newnode->next = *phead;*phead = newnode;}else{SLNode* cur =*phead;while (cur->next){cur = cur->next;}cur->next = newnode;}}
3.5尾删法-----从尾部删除数据
- ①当我们没有链表此时没有删除的东西,所以不能传入空指针
- ②当我们只有一个节点要删除

那么由于我们头指针有所改变,所以函数传参还是传递我们的头指针的地址
- ③当有很多节点

尽量不用->next->next=NULl的形式做判断,当只有一个节点的时候越界访问。
实现一下:
void SLTPopBack(SLNode** phead) {assert(*phead);//头指针不能为空if ((*phead)->next == NULL){free(*phead);*phead = NULL;}else{SLNode* bfend = NULL;SLNode* end = *phead;while (end->next){bfend = end;end = end->next;}free(bfend->next);bfend->next = NULL;} }
3.6头删法

void SLTPopFront(SLNode** phead) {assert(*phead);//当头指针非空SLNode* newnode =(*phead)->next;(*phead)->next = NULL;free(*phead);*phead = newnode; }
![]()
3.7寻找函数
遍历寻找某个值
SLNode* SLFind(SLNode* phead, SLTDataType x) {SLNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;}
3.8修改函数
找到值返回对应位置的指针,然后通过指针修改
void SLMod(SLNode* phead) {int x = 0;printf("请输入你要修改的值:\n");scanf("%d", &x);SLNode* ret = SLFind(phead, x);if (ret){printf("请输入你要修改成什么值\n");int c = 0;scanf("%d", &c);ret->data = c;} }
3.9在pos位置前插入
涉及到头插,就要涉及头指针的改变,那么我们就要传二级指针:
void SLTInsert(SLNode** phead, SLNode* pos, SLTDataType x) {//不能传入空指针assert(pos);if (pos == *phead)//头插{SListPushBack(phead, x);}else{//先遍历到要插入的位置前一个SLNode* pre = *phead;while (pre->next != pos){pre = pre->next;}//然后插入这个新节点,开辟新节点SLNode* newnode = BuySListNode(x);pre->next = newnode;newnode->next = pos;} }
3.10在pos位置后插入

不是不能和头指针相等,是不能为空指针。不可能实现头插
void SLTInsertAfter(SLNode* pos, SLTDataType x) {assert(pos);SLNode* newnode = BuySListNode(x);newnode->next = pos->next;pos->next = newnode; }
3.11在pos位置前删除
3.12在pos位置后一个位置删除
void SLTEraseAfter(SLNode* pos) {//不能传空指针、头指针、和指向尾节点的指针,没有意义assert(pos);assert(pos->next);SLNode* posNext = pos->next;pos->next = posNext->next;free(posNext);posNext = NULL; }
3.13在pos位置删除
void SLTErase(SLNode** phead, SLNode* pos) {assert(pos);//断言不会传入空指针if (pos == *phead){//头删SLTPopFront(phead);}else{SLNode* pre = *phead;while (pre->next != pos){pre - pre->next;}pre->next = pos->next;free(pos);pos = NULL;} }
4.补充链表类型暂时了解
① 单向或者双向

②带头或者不带头

③循环或者非循环

5.结语
今天的重点在于理解单链表的增删查改,特别是什么时候需要传输二级指针,什么时候不传。以上就是本期的所有内容,知识含量蛮多,大家可以配合解释和原码运行理解。创作不易,大家如果觉得还可以的话,欢迎大家三连,有问题的地方欢迎大家指正,一起交流学习,一起成长,我是Nicn,正在c++方向前行的奋斗者,数据结构内容持续更新中,感谢大家的关注与喜欢。
相关文章:
【数据结构和算法初阶(C语言)】链表-单链表(手撕详讲单链表增删查改)
目录 1.前言:顺序表回顾: 1.1顺序表的优缺点 2.主角----链表 2.1链表的概念 2.2定义一个单链表的具体实现代码方式 3.单链表对数据的管理----增删查改 3.1单链表的创建 3.2单链表的遍历实现 3.2.1利用遍历实现一个打印我们链表内容的函数的函数…...
【Go语言】Go语言中的切片
Go语言中的切片 1.切片的定义 Go语言中,切片是一个新的数据类型数据类型,与数组最大的区别在于,切片的类型中只有数据元素的类型,而没有长度: var slice []string []string{"a", "b", "c…...
Qt程序设计-钟表自定义控件实例
本文讲解Qt钟表自定义控件实例。 效果如下: 创建钟表类 #ifndef TIMEPIECE_H #define TIMEPIECE_H#include <QWidget> #include <QPropertyAnimation> #include <QDebug> #include <QPainter> #include <QtMath>#include <QTimer>#incl…...
Redis的发布订阅功能教程,实现实时消息和key过期事件通知功能
Redis的发布订阅 Redis的发布/订阅(Pub/Sub)功能是一种消息传递模式,用于实现消息发布者(publisher)和订阅者(subscriber)之间的消息通信。在这种模式下,消息的发送者(发布者)将消息发送到特定的频道(channel),而订阅了该频道的接收者(订阅者)将会接收到这些消息…...
4核8g服务器能支持多少人访问?
腾讯云4核8G服务器支持多少人在线访问?支持25人同时访问。实际上程序效率不同支持人数在线人数不同,公网带宽也是影响4核8G服务器并发数的一大因素,假设公网带宽太小,流量直接卡在入口,4核8G配置的CPU内存也会造成计算…...
【Android】切换系统全局语言设置
前两种为应用内部处理,第三种为发送广播由系统服务进行处理 使用反射 这种会直接将安卓设置内的语言列表清空,然后将选择的语言设置为系统语言 该方法存在问题,在首次开机后设置会导致国外应用进不去(只对于here地图个别版本) /*** 设置语言…...
【递归】【回溯】Leetcode 112. 路径总和 113. 路径总和 II
【递归】【回溯】Leetcode 112. 路径总和 113. 路径总和 II 112. 路径总和解法:递归 有递归就有回溯 记得return正确的返回上去 113. 路径总和 II解法 递归 如果需要搜索整棵二叉树,那么递归函数就不要返回值 如果要搜索其中一条符合条件的路径ÿ…...
AxureCloud配置文件详细介绍
AxureCloud配置文件详细介绍 原文地址:https://docs.axure.com/axure-cloud/business/custom-settings-json/ 通过修改 customsettings.json 可以修改AxureCloud私有部署的域名、端口、HTTPS、存储目录、是否开启插件等, 默认安装的路径为: C:\Program Files\Axure…...
Centos开机网卡自启动失败
问题背景 每次都要手动启动在这里插入代码片 解决方案: 关闭 NetworkManager 服务 systemctl disable NetworkManager systemctl stop NetworkManager重启就会发现网卡已经可以自动启动了...
华为OD技术面试案例3-2024年
技术一面: 1.手撕代码,算法题: 【最小路径和】 手撕代码通过,面试官拍了照片 2.深挖项目,做过的自认为最好的一个项目,描述做过的项目的工作过程,使用到哪些技术? 技术二面&…...
全面升级!Apache HugeGraph 1.2.0版本发布
图数据库以独特的数据管理和分析能力,在企业数智化转型的过程中正在成为数据治理的核心,根据IDC调研显示,95%的企业认为图数据库是重要的数据管理工具,超过65%的厂商认为在业务上图数据库优于其他选择,尤其是在金融风控…...
WinCC如何与三菱Q系列PLC进行以太网通讯
本文主要描述人机界面WinCC如何与三菱Q系列PLC进行以太网通讯,主要介绍了CPU自带以太网口和扩展以太网模块两种情况以及分别使用TCP、UDP两种协议进行通讯组态步骤及其注意事项。 一、 说明 WinCC从V7.0 SP2版本开始增加了三菱以太网驱动程序,支持和三…...
Spring11、整合Mybatis
11、整合Mybatis 步骤: 导入相关jar包 junit <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version> </dependency> mybatis <dependency><groupId>org.my…...
C语言练习:(力扣645)错误的集合
题目链接:645. 错误的集合 - 力扣(LeetCode) 集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字…...
广和通发布基于MediaTek T300平台的RedCap模组FM330系列及解决方案
世界移动通信大会MWC 2024期间,广和通发布基于MediaTek T300平台的RedCap模组FM330系列,加速5G-A繁荣发展。FM330系列及其解决方案采用全球先进RedCap方案,满足移动宽带和工业互联对高能效的需求。 广和通FM330系列采用全球首款6nm制程且集成…...
代码随想录训练营第六十三天打卡|503.下一个更大元素II 42. 接雨水
503.下一个更大元素II 1.暴力法,和每日温度那一题如出一辙,循环数组用了一个取模运算就解决了。 class Solution { public:vector<int> nextGreaterElements(vector<int>& nums) {int n nums.size();vector<int> result;for (i…...
【web】nginx+php环境搭建-关键点(简版)
一、nginx和php常用命令 命令功能Nginxphp-fpm启动systemctl start nginxsystemctl start php-fpm停止systemctl stop nginxsystemctl stop php-fpm重启systemctl restart nginxsystemctl restart php-fpm查看启动状态systemctl status nginxsystemctl status php-fpm开机自启…...
1、什么是ETF?
ETF是Exchange Traded Fund的英文缩写,中文称为“交易型开放式指数基金”,又称“指数股”。ETF是一种指数投资工具,通过复制标的指数来构建跟踪指数变化的组合证券,使得投资者通过买卖一种产品就实现了一揽子证券的交易。简单来说…...
备战蓝桥杯Day18 - 双链表
一、每日一题 蓝桥杯真题之工作时长 这个题写代码做的话很麻烦,而且我也不一定能写出来,所以我直接就是用的excel来计算的时间和。 使用excel的做法 1.先把文件中的时间复制到excel中。 2.把日期和时间分到两列。 分成两列的步骤: 选中要…...
【大数据】Flink 内存管理(二):JobManager 内存分配(含实际计算案例)
《Flink 内存管理》系列(已完结),共包含以下 4 篇文章: Flink 内存管理(一):设置 Flink 进程内存Flink 内存管理(二):JobManager 内存分配(含实际…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...















