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

【数据结构和算法初阶(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服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…...

【Android】切换系统全局语言设置

前两种为应用内部处理&#xff0c;第三种为发送广播由系统服务进行处理 使用反射 这种会直接将安卓设置内的语言列表清空&#xff0c;然后将选择的语言设置为系统语言 该方法存在问题&#xff0c;在首次开机后设置会导致国外应用进不去(只对于here地图个别版本) /*** 设置语言…...

【递归】【回溯】Leetcode 112. 路径总和 113. 路径总和 II

【递归】【回溯】Leetcode 112. 路径总和 113. 路径总和 II 112. 路径总和解法&#xff1a;递归 有递归就有回溯 记得return正确的返回上去 113. 路径总和 II解法 递归 如果需要搜索整棵二叉树&#xff0c;那么递归函数就不要返回值 如果要搜索其中一条符合条件的路径&#xff…...

AxureCloud配置文件详细介绍

AxureCloud配置文件详细介绍 原文地址&#xff1a;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年

技术一面&#xff1a; 1.手撕代码&#xff0c;算法题&#xff1a; 【最小路径和】 手撕代码通过&#xff0c;面试官拍了照片 2.深挖项目&#xff0c;做过的自认为最好的一个项目&#xff0c;描述做过的项目的工作过程&#xff0c;使用到哪些技术&#xff1f; 技术二面&…...

全面升级!Apache HugeGraph 1.2.0版本发布

图数据库以独特的数据管理和分析能力&#xff0c;在企业数智化转型的过程中正在成为数据治理的核心&#xff0c;根据IDC调研显示&#xff0c;95%的企业认为图数据库是重要的数据管理工具&#xff0c;超过65%的厂商认为在业务上图数据库优于其他选择&#xff0c;尤其是在金融风控…...

WinCC如何与三菱Q系列PLC进行以太网通讯

本文主要描述人机界面WinCC如何与三菱Q系列PLC进行以太网通讯&#xff0c;主要介绍了CPU自带以太网口和扩展以太网模块两种情况以及分别使用TCP、UDP两种协议进行通讯组态步骤及其注意事项。 一、 说明 WinCC从V7.0 SP2版本开始增加了三菱以太网驱动程序&#xff0c;支持和三…...

Spring11、整合Mybatis

11、整合Mybatis 步骤&#xff1a; 导入相关jar包 junit <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version> </dependency> mybatis <dependency><groupId>org.my…...

C语言练习:(力扣645)错误的集合

题目链接&#xff1a;645. 错误的集合 - 力扣&#xff08;LeetCode&#xff09; 集合 s 包含从 1 到 n 的整数。不幸的是&#xff0c;因为数据错误&#xff0c;导致集合里面某一个数字复制了成了集合里面的另外一个数字的值&#xff0c;导致集合 丢失了一个数字 并且 有一个数字…...

广和通发布基于MediaTek T300平台的RedCap模组FM330系列及解决方案

世界移动通信大会MWC 2024期间&#xff0c;广和通发布基于MediaTek T300平台的RedCap模组FM330系列&#xff0c;加速5G-A繁荣发展。FM330系列及其解决方案采用全球先进RedCap方案&#xff0c;满足移动宽带和工业互联对高能效的需求。 广和通FM330系列采用全球首款6nm制程且集成…...

代码随想录训练营第六十三天打卡|503.下一个更大元素II 42. 接雨水

503.下一个更大元素II 1.暴力法&#xff0c;和每日温度那一题如出一辙&#xff0c;循环数组用了一个取模运算就解决了。 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的英文缩写&#xff0c;中文称为“交易型开放式指数基金”&#xff0c;又称“指数股”。ETF是一种指数投资工具&#xff0c;通过复制标的指数来构建跟踪指数变化的组合证券&#xff0c;使得投资者通过买卖一种产品就实现了一揽子证券的交易。简单来说…...

备战蓝桥杯Day18 - 双链表

一、每日一题 蓝桥杯真题之工作时长 这个题写代码做的话很麻烦&#xff0c;而且我也不一定能写出来&#xff0c;所以我直接就是用的excel来计算的时间和。 使用excel的做法 1.先把文件中的时间复制到excel中。 2.把日期和时间分到两列。 分成两列的步骤&#xff1a; 选中要…...

【大数据】Flink 内存管理(二):JobManager 内存分配(含实际计算案例)

《Flink 内存管理》系列&#xff08;已完结&#xff09;&#xff0c;共包含以下 4 篇文章&#xff1a; Flink 内存管理&#xff08;一&#xff09;&#xff1a;设置 Flink 进程内存Flink 内存管理&#xff08;二&#xff09;&#xff1a;JobManager 内存分配&#xff08;含实际…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…...