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

数据结构之单链表(超详解)

在这里插入图片描述


在这里插入图片描述


文章目录

  • 1. 单链表
    • 1.1 概念、结构
    • 1.2 结点
      • 1.2.1 链表的性质
  • 2. 链表的打印
  • 3. 尾插、头插
    • 创建结点
    • 尾插
    • 头插
  • 4. 尾删、头删
    • 尾删
    • 头删
  • 5. 查找指定结点
  • 6. 指定位置之前、之后插入数据
    • 指定位置之前插入数据
    • 指定位置之后插入数据
  • 7. 删除指定位置结点
  • 7.1 删除指定位置之后结点
  • 8. 链表的销毁
  • 9. 单链表代码实现

1. 单链表

1.1 概念、结构

链表也是线性表的一种。

概念:链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。(即链表在物理结构上不一定连续,在逻辑结构上一定连续)
在这里插入图片描述

1.2 结点

每节"车厢"都是独立申请下来的空间,我们称之为“节点/结点”

结点的组成主要有两个部分
1. 当前结点要保存的数据
2. 保存下⼀个结点的地址(指针变量)。

上图指针变量 plist保存的是第一个结点的地址,我们称plist此时“指向”第一个结点,如果我们希望plist“指向”第二个结点时,只需要修改plist保存的内容为0x0012FFA0。
链表中每个结点都是独立申请的(即需要插入数据时才去申请一块结点的空间),我们需要通过指针变量来保存下⼀个结点位置才能从当前结点找到下一个结点。

对应实现结点的结构体代码:
在这里插入图片描述

1.2.1 链表的性质

  1. 链式机构在逻辑上是连续的,在物理结构上不一定连续;
  2. 结点⼀般是从堆上申请的;
  3. 从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

2. 链表的打印

结点创建
void SLTTest01()
{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;将4个节点连接起来node1->next = node2;node2->next = node3;node3->next = node4;node4->next = NULL;SLTPrint(plist);
}

在这里插入图片描述

在这里插入图片描述
显然我们每次都要一个接一个创建结点,并让结点连接起来过于麻烦。因此,我们可以考虑封装成一个函数,这个函数用来创建结点

3. 尾插、头插

创建结点

需要进行尾插,头插的操作首先需要创建结点
在这里插入图片描述

尾插

在尾插的时候需要考虑以下几点:

  1. 如果为空链表该如何处理
  2. 如何让两个结点相连
  3. 如何找到尾部结点
    在这里插入图片描述

在这里插入图片描述

头插

相比于尾插,头插不需要考虑链表是否为空的情况,因为只要让新的结点头插到NULL即可
在这里插入图片描述

4. 尾删、头删

尾删

进行尾删操作需要考虑以下因素:

  1. 链表是否为空,空的话不能进行尾删
  2. 遍历链表找到尾结点
  3. 保存尾结点的前一个结点
  4. 释放尾结点,让前一个结点指向NULL
    在这里插入图片描述
    在这里插入图片描述

头删

头删需要考虑以下因素:

  1. 链表是否为空
  2. 保存第二个有效结点
  3. 释放第一个有效结点,让pphead指向第二个有效结点
    在这里插入图片描述

5. 查找指定结点

在这里插入图片描述
在这里插入图片描述

6. 指定位置之前、之后插入数据

指定位置之前插入数据

  1. 链表是否为空
  2. 指定位置值的结点是否存在
  3. 如果指定位置的结点时头节点,则头插即可
  4. 遍历链表找到指定结点的前一个结点
    在这里插入图片描述

指定位置之后插入数据

在这里插入图片描述

7. 删除指定位置结点

  1. 链表是否为空
  2. 指定位置结点是否存在
  3. 指定位置结点是否是头结点
  4. 遍历链表找到pos结点的前一个结点
  5. 释放pos结点
    在这里插入图片描述

7.1 删除指定位置之后结点

在这里插入图片描述

8. 链表的销毁

在这里插入图片描述

9. 单链表代码实现

Slist.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
//针对顺序表:中间/头部插入效率低下、增容降低运行效率、增容造成空间浪费
//因此有了单链表
//链表也是线性表的一种
//链表是由一个一-个的节点组成
//组成:数据  指向下一个节点的指针typedef int DataType;//可能存储整形,字符型等等typedef struct SlistNode
{DataType data;//节点数据struct SlistNode* next;//指向下一个节点的指针
}SLTNode;//链表的打印
void SLTPrint(SLTNode* phead);
//创建节点
SLTNode* SLTBuyNode(DataType x);
//尾插
void SLTPushBack(SLTNode** pphead, DataType x);
//头插
void SLTPushFront(SLTNode** pphead, DataType x);
//尾删
void SLTPopBack(SLTNode** pphead);
//头删
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, DataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, DataType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, DataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos后节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SLTDesTroy(SLTNode** pphead);

Slist.c
#define _CRT_SECURE_NO_WARNINGS 1#include"Slist.h"//链表的打印
void SLTPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL\n");
}
//创建节点
SLTNode* SLTBuyNode(DataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}//创建成功newnode->data = x;newnode->next = NULL;return newnode;
}
//尾插
void SLTPushBack(SLTNode** pphead, DataType x)
{assert(pphead);//空链表和非空链表SLTNode* newnode = SLTBuyNode(x);//如果是空链表if (*pphead == NULL){*pphead = newnode;}else {//找尾节点SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}//ptail指向的就是尾节点ptail->next = newnode;}
}
//头插
void SLTPushFront(SLTNode** pphead, DataType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);newnode->next = *pphead;*pphead = newnode;
}
//尾删
void SLTPopBack(SLTNode** pphead)
{//链表不能为空assert(pphead && *pphead);//链表只有一个节点if ((*pphead)->next == NULL) //-> 优先级高于*{free(*pphead);*pphead = NULL;}else {//链表有多个节点SLTNode* prev = *pphead;SLTNode* ptail = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}free(ptail);ptail = NULL;prev->next = NULL;}
}
//头删
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}
//查找
SLTNode* SLTFind(SLTNode* phead, DataType x)
{SLTNode* pcur = phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}//pcur == NULLreturn NULL;
}
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, DataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* newnode = SLTBuyNode(x);//若pos == *pphead 说明是头插if (pos == *pphead){SLTPushFront(pphead, x);}else {SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;}
}
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, DataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);//先连接后面在前面newnode->next = pos->next;pos->next = newnode;
}
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);//pos是头节点if (pos == *pphead){SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;}else{//pos不是头节点SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}
//删除pos后节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}
//销毁链表
void SLTDesTroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}//pcur为NULL*pphead = NULL;
}

test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Slist.h"//链表是由一个一个的节点组成
//创建几个节点//第一个节点                 *plist <---> **pphead
//指向第一个节点的指针         plist <---> *pphead
//指向第一个节点的指针的地址    &plist <---> pphead
void SLTTest01()
{//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;//将4个节点连接起来//node1->next = node2;//node2->next = node3;//node3->next = node4;//node4->next = NULL;//调用链表的打印SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushFront(&plist, 5);SLTPrint(plist);//SLTPopBack(&plist);//SLTPopBack(&plist);//SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);//SLTPrint(plist);//SLTPopFront(&plist);//SLTPopFront(&plist);SLTPrint(plist);//测试查找SLTNode* find = SLTFind(plist, 5);if (find == NULL){printf("没有找到\n");}else {printf("找到了\n");}SLTInsert(&plist, find, 6);//SLTErase(&plist, find);//SLTEraseAfter(find);//SLTErase(&plist, find);SLTPrint(plist);SLTDesTroy(&plist);SLTPrint(plist);}int main()
{SLTTest01();return 0;
}

在这里插入图片描述


在这里插入图片描述


相关文章:

数据结构之单链表(超详解)

文章目录 1. 单链表1.1 概念、结构1.2 结点1.2.1 链表的性质 2. 链表的打印3. 尾插、头插创建结点尾插头插 4. 尾删、头删尾删头删 5. 查找指定结点6. 指定位置之前、之后插入数据指定位置之前插入数据指定位置之后插入数据 7. 删除指定位置结点7.1 删除指定位置之后结点8. 链表…...

告别编程困惑:GDB、冯诺依曼、操作系统速通指南

&#x1f31f; 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。&#x1f31f; &#x1f6a9;用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 目录 前言 一…...

网络分析工具-tcpdump

文章目录 前言一、tcpdump基础官网链接命令选项详解常规过滤规则tcpdump输出 一、tcpdump实践HTTP协议ICMP状态抓包 前言 当遇到网络疑难问题的时候&#xff0c;抓包是最基本的技能&#xff0c;通过抓包才能看到网络底层的问题 一、tcpdump基础 tcpdump是一个常用的网络分析工…...

基于AI边缘计算盒子的智慧零售场景智能监控解决方案

一、方案背景 随着零售业的快速发展&#xff0c;传统零售模式面临着诸多挑战&#xff0c;如人力成本高、管理效率低、顾客体验不佳等。智慧零售借助人工智能、物联网等技术手段&#xff0c;实现对零售场景的全面感知和智能管理。AI边缘计算盒子作为智慧零售的关键技术之一&…...

STM32G431收发CAN

1.硬件连接 PB8作为CAN_RX&#xff0c;PB9作为CAN_TX&#xff0c;连接一个CAN收发器TJA1051T/3 2. CubeMX里配置CAN 设置连接FDCAN1的参数&#xff0c;使用1个标准过滤器&#xff0c;波特率位500K 使能FDCAN1的中断 3 自动生成代码 3.1 初始化 static void MX_FDCAN1_In…...

如何得到深度学习模型的参数量和计算复杂度

1.准备好网络模型代码 import torch import torch.nn as nn import torch.optim as optim# BP_36: 输入2个节点&#xff0c;中间层36个节点&#xff0c;输出25个节点 class BP_36(nn.Module):def __init__(self):super(BP_36, self).__init__()self.fc1 nn.Linear(2, 36) # …...

2025年股指期货每月什么时候交割?

股指期货交割日是指期货合约到期时&#xff0c;买卖双方根据合约规定的指数价值进行现金结算的日期。在中国市场中&#xff0c;股指期货的交割日通常是合约到期月份的第三个星期五。这一规律适用于所有股指期货合约&#xff0c;无论是当月、下月合约&#xff0c;还是季度月合约…...

自从学会Git,感觉打开了一扇新大门

“同事让我用 Git 提交代码&#xff0c;我居然直接把项目文件压缩发过去了……”相信很多初学者都经历过类似的窘境。而当你真正掌握 Git 时&#xff0c;才会发现它就像一本魔法书&#xff0c;轻松解决代码管理的种种难题。 为什么 Git 能成为程序员的标配工具&#xff1f;它究…...

Ansys Discovery 中的网格划分方法:探索模式

本篇博客文章将介绍 Ansys Discovery 中可用于在探索模式下进行分析的网格划分方法。我们将在下一篇博客中介绍 Refine 模式下的网格划分技术。 了解 Discovery Explore 模式下的网格划分 网格划分是将几何模型划分为小单元以模拟系统在不同条件下的行为的过程。这是通过创建…...

关于 AWTK 和 Weston 在旋转屏幕时的资源消耗问题

关于 AWTK 和 Weston 在旋转屏幕时的资源消耗问题&#xff0c;首先需要理解这两者旋转的本质区别及其资源开销。 AWTK的屏幕旋转&#xff1a; AWTK旋转的实现方式&#xff1a; AWTK 是一个用户界面工具包&#xff0c;它通过图形渲染系统处理所有控件和窗口的旋转。当你使用 w…...

grouped.get_group((‘B‘, ‘A‘))选择分组

1. df.groupby([team, df.name.str[0]]) df.groupby([team, df.name.str[0]]) 这一部分代码表示对 DataFrame df 按照 两个条件 进行分组&#xff1a; 按照 team 列&#xff08;即团队&#xff09;。按照 name 列的 首字母&#xff08;df.name.str[0]&#xff09;。 df.name.s…...

HTML——66.单选框

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>单选框</title></head><body><!--input元素的type属性&#xff1a;(必须要有)--> <!--单选框:&#xff08;如所住省会&#xff0c;性别选择&…...

Couchbase 和数据湖技术的区别、联系和相关性分析

Couchbase 和数据湖技术&#xff08;如 Delta Lake、Apache Hudi、Apache Iceberg&#xff09;分别是两类不同的数据存储与管理系统&#xff0c;但它们也可以在特定场景中结合使用&#xff0c;以下是它们的区别、联系和相关性分析&#xff1a; 区别&#xff1a; 1. 核心用途&a…...

springboot3 性能优化

Spring Boot 3 是基于 Spring Framework 6 的最新版本,支持 Java 17,并引入了多项改进,包括原生镜像支持、性能提升和现代化开发支持。以下是对 Spring Boot 3 应用进行全面优化的详细步骤: 一、开发环境优化 1. 使用最新版本 确保依赖版本为最新: Spring Boot 3.x。 J…...

C++之运算符重载详解篇

1.概念 重载概念&#xff1a; C 允许在同一作用域中的某个函数和运算符指定多个定义&#xff0c;分别称为函数重载和运算符重载。 运算符重载概念&#xff1a;对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型 这里主要介绍…...

深度学习应用工程化中的节能减排最佳实践

文章大纲 简介为什么要在制造业节能减排能耗估算显卡能耗CPU 能耗树莓派能耗加速卡能耗硬件层面的改进边缘端硬件简介树莓派 + 加速卡软件层面的改进检测逻辑的改进算法层面改进深度学习模型训练,推理,量化的优化外网参考参考文献简介 为什么要在制造业节能减排 一、制造业…...

电脑文件msvcp110.d丢失的解决方法

电脑运行故障全解析&#xff1a;从文件丢失到系统报错&#xff0c;打造无忧使用环境 在数字化浪潮中&#xff0c;电脑作为我们工作、学习和娱乐的得力助手&#xff0c;其稳定运行至关重要。然而&#xff0c;在实际使用过程中&#xff0c;我们难免会遇到各种各样的问题&#xf…...

xdoj isbn号码

ISBN 号码 问题描述 每一本正式出版的图书都有一个 ISBN 号码与之对应&#xff0c;ISBN 码包括 9 位数字、1 位识别码和 3 位分隔符&#xff0c;其规定格式如"x-xxx-xxxxx-x"&#xff0c; 其中符号“-”是分隔符&#xff08;键盘上的减号&#xff09;&#xff0c;最…...

qt的utc时间转本地时间

代码如下: #include <QCoreApplication> #include <QDateTime> #include <QDebug>int main(int argc...

mariadb变更数据存放目录

1、停止mariadb服务 # systemctl stop maraidb.server 2、创建数据目录 # mkdir /opt/mysql # chown -R mysql:mysql /opt/mysql 3、配置mariadb 3.1 配置文件说明 # cd /etc/mysql/ && ls -l my.cnf为主配置文件&#xff0c;其他的为子配置&#xff0c;同时配置…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...