【数据结构】图文并茂,通过逻辑图带你轻松拿捏链表,实现各种接口功能

在这里插入图片描述

君兮_的个人主页

勤时当勉励 岁月不待人

C/C++ 游戏开发

Hello,米娜桑们,这里是君兮_,我们接着之前讲过的顺序表来继续介绍初阶数据结构的内容,今天给大家带来的是有关链表的基本知识和各种接口功能的实现
好了,废话不多说,开始今天的学习吧!

链表

  • 一.链表的基础知识
    • 1.链表的概念与基本结构
    • 2.链表的分类
  • 二.无头单链表的实现
    • 1.初始化链表 BuySListNode
    • 2.打印链表 SLTPrint
    • 3.头插 SLTPushFront与头删 SLTPopFront
      • 头插
      • 头删
    • 4.尾插SLTPushBack和尾删 SLTPopBack
      • 尾插
      • 尾删
  • 总结

一.链表的基础知识

1.链表的概念与基本结构

  • 概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
  • 链表链表,表如其名,链表的结构就如同被连接起来了,只不过在中间连接链表的“绳索”是指针。
    在这里插入图片描述
  • 从基本结构图中我们可以看出:
    1.链式结构在逻辑上是连续的,但与顺序表不同,在物理上链表是不一定连续的
    2.现实中,链表的节点一般都是从堆上申请出来的。
    3.从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能连续,也可能不连续。

2.链表的分类

  • 在实际中链表的结构非常多样,下面就简单的介绍几种
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 虽然链表有多种结构,但是最常用的还是这两种
    在这里插入图片描述
  • 1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
  • 2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我也会带大家逐一实现代码。

二.无头单链表的实现

  • 由于我们是初阶数据结构,且这是有关链表的第一篇博客,我们就先从最简单的无头单链表开始实现。
  • 首先我们先把需要的几个功能的接口列出来然后咱们来一个一个介绍。

说明:以下包括后面的所有代码的函数名称等都是我根据该函数的功能编的,也就是说这些函数名等不唯一,你也可以起别的名字,不影响链表的使用,但就像给孩子取名一样,我们都不希望我们的孩子的名字叫狗蛋,二狗子什么的,实际上,在函数的命名中你瞎起名字就和这些差不多,因此我建议无论是现在还是以后的函数的命名最好都按照功能来命名,这样既增加了代码的可读性,也让人一看便知各个函数的功能。

#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* BuySListNode(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);

// 在pos之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);

// 在pos以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

// 删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos);

// 删除pos的后一个位置
void SLTEraseAfter(SLTNode* pos);
//修改pos位置的值
void SLTModify(SLTNode**pphead, SLTNode* pos, SLTDataType x);
// 单链表的销毁
void SListDestroy(SLTNode** pphead);
  • 注意:对接口的声明都包含在头文件中
  • 先讲一下这里面需要注意的几个地方:
  • 1.第一处的 typedef 实际是为了方便我们的使用,因为我们也不知道我们的链表是用来存储什么类型的数据的,因此我们这里就定义一个SLDataType,下面的代码中统一把数据类型用它来代替,这样一来,我们以后想要改变存储的数据类型,只需要改动这里即可,比如我们现在想要存储double类型的数据
typedef double SLDataType;
  • 2.关于我们的链表的结构体
typedef struct SListNode
{
    SLTDataType Data;
    struct SListNode * next;

}SLTNode;
  • 我们说了,我们的链表的连接是通过指针来实现的,因此我们的结构体中第一个成员是该节点存储的值,第二个成员则是一个该结构体的指针,指向的是下一个节点的地址。

1.初始化链表 BuySListNode

  • 当我们想使用我们的链表时,首先就像变量一样需要先把它初始化一下
//初始化链表
SLTNode* BuySListNode(SLTDataType x)
{
    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    if (newnode == NULL)
    {
        perror("malloc failed:");
        exit(-1);
    }
    newnode->Data = x;
    newnode->next = NULL;
    return newnode;

}
  • 我们首先通过malloc为我们链表的一个节点开辟了空间,然后通过perror判断了我们的malloc是否成功,如果成功,我们就把该链表的值置为我们输入的x,由于此时只有它一个节点,因此next置空,这样我们的一个节点就初始化好了。

2.打印链表 SLTPrint

  • 当我们初始化成功后,我们就想把我们的链表打印一下,看看我们的链表是否成功初始化了,因此我们继续来写打印链表的函数
//打印链表
void SLTPrint(SLTNode* phead)
{
    SLTNode* cur = phead;
    while (cur)
    {
        printf("%d->", cur->Data);
        cur = cur->next;
    }
    printf("NULL\n");
}
  • 我们定义了一个结构体指针cur指向传入的链表的表头,当cur不为空时,我们就打印一下此时该节点中的Data,并通过next找到下一个节点
  • 由于我们链表的最后一个元素是NULL,因此我们最后把链表中所有节点都打印完后,在最后再补上一个NULL。

在这里插入图片描述

  • 效果如上图

3.头插 SLTPushFront与头删 SLTPopFront

  • 头插与头删顾名思义,就是在链表表头插入节点或者删除链表表头的节点

头插

//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
    SLTNode* newnode = BuySListNode(x);
    newnode->next = *pphead;
    *pphead = newnode;
}
  • 头插的逻辑图是这样的
    在这里插入图片描述
    在这里插入图片描述

头删

//头删
void SLTPopFront(SLTNode** pphead)
{
    //空
    assert(*pphead);
    //非空;
    SLTNode* newhead = (*pphead)->next;//保存一下下一个节点的地址
    free(*pphead);
    *pphead = newhead;
}
  • 头删的逻辑图
  • 首先先判断*pphead是否为空,如果为空,说明这个链表压根不存在
    在这里插入图片描述
    在这里插入图片描述

4.尾插SLTPushBack和尾删 SLTPopBack

  • 与前面同理,尾插和尾删是作用于链表的最后的

尾插

//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
    SLTNode* newnode = BuySListNode(x);
    SLTNode* tail = *pphead;
    //链表中没有节点时
    if (*pphead == NULL)
    {
        *pphead = newnode;
    }
    else
    {
        //不为空时
        while (tail->next)
        {
            tail = tail->next;
        }
        tail->next = newnode;

    }
}
  • 我们知道链表的最后一个节点的next存放的地址为空,我们来通过逻辑图分析一下
  • 首先还是特殊情况,当我们的链表中没有节点时,那我们就把头指针直接指向需要插入的节点就行。
    在这里插入图片描述
    在这里插入图片描述

尾删

//尾删
void SLTPopBack(SLTNode** pphead)
{
    //为空
    assert(*pphead);
    //只有一个节点
    if ((*pphead)->next == NULL)
    {
        free(*pphead);
        *pphead = NULL;
    }
    //不为空且有多个节点
    else
    {
        SLTNode* tail = *pphead;
        while (tail->next->next)
        {
            tail = tail->next;
        }
        free(tail->next);
        tail->next = NULL;


    }
}
  • 还是先来分析特殊情况,先通过assert断言来判断一下该链表是否为空,其次,如果这个链表只有一个节点时,我们指向把该节点free释放掉再置空即可,不需要其他操作。
  • 一般情况的逻辑图
    在这里插入图片描述
    在这里插入图片描述

总结

  • 由于篇幅有限,今天的内容到这里就结束了,之后我们会把剩下没讲的接口讲完然后再带大家做几道oj题让大家更加熟悉链表的使用。相信如果你能一直跟着坚持下去那么你链表这一块的初阶知识就一定没什么问题啦!切记要自己上手敲敲代码哦!

  • 好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/54906.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【uniapp】实现买定离手小游戏

前言 最近玩了一个小游戏&#xff0c;感觉挺有意思&#xff0c;打算放进我的小程序【自动化小助手】里面&#xff0c;“三张押一张&#xff0c;专押花姑娘&#xff01;”&#xff0c;从三张卡牌&#xff0c;挑选一张&#xff0c;中奖后将奖励进行发放&#xff0c;并且创建下一…

Github-Copilot初体验-Pycharm插件的安装与测试

引言&#xff1a; 80%代码秒生成&#xff01;AI神器Copilot大升级 最近copilot又在众多独角兽公司的合力下&#xff0c;取得了重大升级。GitHub Copilot发布还不到两年&#xff0c; 就已经为100多万的开发者&#xff0c;编写了46%的代码&#xff0c;并提高了55%的编码速度。 …

AMEYA详解松下Panasonic HF SSOP 1 Form A AQY PhotoMOS继电器

Panasonic HF SSOP 1 Form A AQY PhotoMOS继电器采用微型SSOP封装&#xff0c;具有600V的负载电压和1500Vrms 的I/O隔离电压 这些继电器具有8Ω的低导通电阻和高速运行的特点&#xff0c;SSOP封装旨在实现高密度安装。Panasonic HF SSOP AQY PhotoMOS继电器适用于从测试和测量设…

【HDFS】Block、BlockInfo、BlockInfoContiguous、BlockInfoStriped的分析记录

本文主要介绍如下内容: 关于几个Block类之间的继承、实现关系;针对文章标题中的每个类,细化到每个成员去注释分析列出、并详细分析BlockInfo抽象类提供的抽象方法、非抽象方法的功能针对几个跟块组织结构的方法再进行分析。moveBlockToHead、listInsert、listRemove等。一、…

从引入并集成多LLM到发布自研模型,RPA与LLM的融合进度怎样了?

RPA厂商对于大语言模型&#xff08;LLM&#xff0c;Large Language Model&#xff09;的应用&#xff0c;比大家想象的还要早一些。 毕竟&#xff0c;2019年兴起的这一波RPA热&#xff0c;背后都是因为AI技术。没有AI技术与RPA的融合&#xff0c;也就没有现在的RPA。 为了全力…

flutter开发实战-旋转loading指示器

flutter开发实战-旋转loading指示器。 一、交织动画 有些时候我们可能会需要一些复杂的动画&#xff0c;这些动画可能由一个动画序列或重叠的动画组成。一个动画组合在不同阶段包含了多种动画&#xff0c;要实现这种效果&#xff0c;需要使用交织动画&#xff08;Stagger Anim…

通过社区参与解锁早期增长:Maven 远程医疗平台概览

Maven通过用户导向的渐进式验证&#xff0c;找到了一个被忽视的巨大女性医疗服务市场&#xff0c;作为女性医疗保健的先行者&#xff0c;已服务超过1500万用户&#xff0c;目前估值已达$14亿。本文将深入探索Maven实现产品市场匹配的三个阶段&#xff0c;从如何验证初始的市场机…

基于微信机器人的二次开发

使用微信ipad协议来开发微信机器人&#xff0c;可以开发的项目很多&#xff0c;例如一些娱乐机器人、云发单系统&#xff0c;私域流量的智能管理和营销拓客&#xff0c;还有一些自动采集和发朋友圈的云端系统等。每个行业都有需求这样的系统应用&#xff0c;在线教育、金融、电…

接口自动化代码不会写?试试RunnerGo

RunnerGo支持自动化测试功能&#xff0c;RunnerGo的工作流程是&#xff1a;接口管理-场景管理-性能测试-自动化测试&#xff0c;所以自动化测试的运行内容为场景下的用例&#xff0c;我们可以在“场景管理”中预先配置好该场景下的用例&#xff0c;也可以在自动化测试中创建用例…

Pytorch入门学习——快速搭建神经网络、优化器、梯度计算

我的代码可以在我的Github找到 GIthub地址 https://github.com/QinghongShao-sqh/Pytorch_Study 因为最近有同学问我如何Nerf入门&#xff0c;这里就简单给出一些我的建议&#xff1a; &#xff08;1&#xff09;基本的pytorch&#xff0c;机器学习&#xff0c;深度学习知识&a…

类Blip2的视觉文本多模态算法

一、Blip2出现的意义不比ChatGPT差 BLIP-2: Bootstrapping Language-Image Pre-training with Frozen Image Encoders and Large Language Models 论文链接&#xff1a;https://arxiv.org/abs/2301.12597 代码仓库&#xff1a;https://github.com/salesforce/LAVIS/tree/mai…

【数据结构】二叉搜索树

文章目录 前言一、概念二、实现1.基本说明①要点②基本框架 2.接口实现①find——查找二叉树的结点②Insert——插入结点③Print——中序遍历打印二叉树的值④Erase——删除结点情况细分 源码总结 前言 普通的二叉树是不能进行增删改查的,或者说没意义&#xff0c;需要根据二叉…

hbuilderx主题色分享-github风格

效果 步骤 hbuilderx总共有三种主题&#xff0c;绿柔主题Default,酷黑主题Monokai,雅黑主题Atom One Dark,修改主题色是基于三种主题之一的&#xff0c;不能直接创建一个新主题&#xff0c;比如下方配置是基于Atom One Dark(对象名为[Atom One Dark])&#xff0c;则当前hbuild…

JavaSE【类和对象(1)】(重点:this引用、构造方法)

目录 一、类的定义方式以及实例化 1.面向对象 Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在Java的世界里一切皆为对象。 2.类的定义和使用 1.在java中定义类时需要用到class关键字 3.类的实例化 4.类实例化的使用 二、this引用 …

Redis 哨兵 (sentinel)

是什么 官网理论&#xff1a;https://redis.io/docs/management/sentinel/ 吹哨人巡查监控后台 master 主机是否故障&#xff0c;如果故障了根据投票数自动将某一个从库转换为新主库&#xff0c;继续对外服务。 作用&#xff1a;无人值守运维 哨兵的作用&#xff1a; 1…

策略路由实现多ISP接入Internet

组网需求&#xff1a; 企业分别从ISP1和ISP2租用了一条链路 PC3用户上网访问Server1时走ISP1PC4用户上网访问Server1时走ISP2 拓扑图 一、ISP1 运营商 R1路由器 <Huawei>sys [Huawei]sys R1 [R1]un in en[R1]int g0/0/0 [R1-GigabitEthernet0/0/0]ip addr 2.2.2.2 2…

Linux系统管理:虚拟机Rocky Linux安装

目录 一、理论 1.Rocky Linux 2.NetworkManager配置 3.ipaddress 配置文件 4.nmtui 配置 ipaddress 二、实验 1.虚拟机Rocky Linux安装准备阶段 2.安装Rocky Linux 3.进入系统 三、问题 1.网络配置文件权限不够 一、理论 1.Rocky Linux &#xff08;1&#xff0…

UE5初学者快速入门教程

虚幻引擎是一系列游戏开发工具&#xff0c;能够将 2D 手机游戏制作为 AAA 游戏机游戏。虚幻引擎 5 用于开发下一代游戏&#xff0c;包括Senuas Saga: Hellblade 2、Redfall&#xff08;来自 Arkane Austin 的合作射击游戏&#xff09;、Dragon Quest XII: The Flames of Fate、…

第一堂棒球课:MLB全明星发展历程·棒球1号位

MLB全明星发展历程 1. MLB全明星的起源 MLB全明星是什么&#xff1f; MLB全明星&#xff0c;也就是MLB All-Stars&#xff0c;是指美国职业棒球大联盟&#xff08;Major League Baseball, MLB&#xff09;在每年举办的全明星赛。这项赛事汇集了全联盟各队的顶级球员&#xff…

基于C语言 --- 自己写一个扫雷小游戏

C语言程序设计笔记---020 初阶扫雷小游戏(开源)1、arr_main2.c程序大纲2、arr_game2.h3、arr_game2.c3.1、 自定义初化函数 InitBoard( ) 和 自定义显示函数 DisPlayBoard( )3.2、 自定义布置雷函数 SetMine( )3.4、 自定义排查雷函数 FindMine( ) 4、结束语 初阶扫雷小游戏(开…