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

news2024/9/20 1:09:51

在这里插入图片描述

君兮_的个人主页

勤时当勉励 岁月不待人

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题让大家更加熟悉链表的使用。相信如果你能一直跟着坚持下去那么你链表这一块的初阶知识就一定没什么问题啦!切记要自己上手敲敲代码哦!

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

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

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32(HAL)串口中断接收

目录 1、简介 2 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 串口外设配置 2.3 项目生成 3、KEIL端程序整合 1、简介 本文对HAL串口中断函数进行介绍。 2 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 串口外设配置 2.3 项目生成 3、KEIL端程序整合 首先在main.c文件中进行…

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

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

深入理解 Java Bean 的生命周期及各个阶段解析

目录 引言&#xff1a;一、什么是Java Bean二、Bean的生命周期概述三、Bean的创建阶段四、属性设置阶段初始化阶段六、使用阶段七、销毁阶段 引言&#xff1a; Java Bean是Java编程中经常使用的重要概念&#xff0c;它是可重用、可移植、可序列化的组件。在Java开发中&#xf…

绝杀 GETPOST 嵌套的 JSON 参数

JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;常用于Web应用程序中的数据传输。在HTTP数据包信息传递时&#xff0c;JSON扮演着非常正常的角色&#xff0c;因为它是一种通用的数据格式&#xff0c;可以被多种编程语言和应用程…

Linux远程连接mysql 出错plugin caching_sha2_password could not be loaded:

问题描述&#xff1a; 今天使用SQLyog远程连接mysql时出错plugin caching_sha2_password could not be loaded问题。 但在本地cmd 进入命令行窗口&#xff1a;输入命令连接远程连接mysql&#xff0c;发现可以顺利连接。 主要问题是 MySQL可视化工具&#xff08;如&#xff1a…

Excel技巧 - 管理规则设置一行变色

如何设置某一列单元格的值大于一个值时&#xff0c;该单元格所在的一整行都变色呢&#xff1f; 1、先框选内容区域&#xff0c;点击开始&#xff0c;条件格式&#xff0c;新建规则 2、如果销量大于20&#xff0c;则该行都变为绿色 编辑格式选择&#xff1a;使用公式确定要设置…

Centos7 如何用命令直接更改配置文件里面内容

环境&#xff1a; Centos7.7 问题描述&#xff1a; Centos7 如何用命令直接更改配置文件里面内容 ifcfg-bond1文件里面DNS想替换改成114 解决方案&#xff1a; 1.使用sed命令 sed -i -e "s:匹配参数.*:匹配参数替换后的内容:g" 对应的文件路径本案例命令 se…

2022年全国硕士研究生入学统一考试管理类专业学位联考写作试题——解析版

四、写作&#xff1a;第56&#xff5e;57小题&#xff0c;共65分。其中论证有效性分析30分&#xff0c;论说文35分。 56.论证有效性分析&#xff1a;分析下述论证中存在的缺陷和漏洞&#xff0c;选择若干要点&#xff0c;写一篇600字左右的文章&#xff0c;对该论证的有效性进…

【iOS】多线程 锁问题总结

文章目录 前言1. 你理解的多线程优点缺点 2. atomic 和 nonatomic 的区别及其作用3. GCD的队列类型 - 三种队列类型4. GCD的死锁问题5. 多线程之间的区别和联系6. 进程和线程&#xff1f;进程间的通信方式线程间的通信方式 6. iOS的线程安全手段如何保证 前言 iOS 锁和多线程的…

【python小知识】python同一个函数并行计算

在Python中&#xff0c;我们可以使用多种方式来实现并行计算&#xff0c;例如使用多进程、多线程和协程等。在本文中&#xff0c;我们将重点介绍如何使用Python内置模块multiprocessing来实现同一个函数的并行计算&#xff0c;带有详细的代码和讲解。 multiprocessing模块是Pyt…

python与深度学习(十三):CNN和IKUN模型

目录 1. 说明2. IKUN模型2.1 导入相关库2.2 建立模型2.3 模型编译2.4 数据生成器2.5 模型训练2.6 模型保存2.7 模型训练结果的可视化 3. IKUN的CNN模型可视化结果图4. 完整代码 1. 说明 本篇文章是CNN的另外一个例子&#xff0c;IKUN模型&#xff0c;是自制数据集的例子。之前…

网络基础-认识每层的设备和每层的特点用途

目录 网络层次常见设备各层介绍数据链路层网络层传输层应用层 网络层次 常见设备 各层介绍 数据链路层 有了MAC地址。数据链路层工作在局域网中的&#xff0c;以帧为单位进行传输和处理数据。 网络层 网络层有了IP。不同的网络通过路由器连接成为互联网 路由器的功能:   …

element-ui中Notification 通知自定义样式、按钮及点击事件

Notification 通知用于悬浮出现在页面角落&#xff0c;显示全局的通知提醒消息。 一、自定义html页面 element-ui官方文档中说明Notification 通知组件的message 属性支持传入 HTML 片段&#xff0c;但是示例只展示了简单的html片段&#xff0c;通常不能满足开发中的更深入需要…

企业如何做好供应商管理?

在现代商业竞争激烈的环境下&#xff0c;供应商管理成为企业取得成功的重要因素之一。十年的供应商管理经验告诉我&#xff0c;建立稳固的合作关系并且持续改进供应链是企业蓬勃发展的关键。 阅读本文您将可以了解&#xff1a;1、供应商管理的重要性&#xff1b;2、管理供应商…

基于多线程实现服务器并发

看大丙老师的B站视频总结的笔记19-基于多线程实现服务器并发分析_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1F64y1U7A2/?p19&spm_id_frompageDriver&vd_sourcea934d7fc6f47698a29dac90a922ba5a3 思路&#xff1a;首先accept是有一个线程的&#xff0c;另外…

apple pencil一代的平替有哪些品牌?好用的苹果平替笔

现在几乎每个人都有一台平板iPad&#xff0c;这可以帮助他们解决很多工作和学习上的问题&#xff0c;比如在工作中处理文件&#xff0c;做一些简单的PPT&#xff0c;如果只用一根手指在iPad上触控的话&#xff0c;就会出现一些点触不准确的地方。所以&#xff0c;为iPad配备一支…

MySQL下载安装与配置以及卸载(最简单最详细的步骤)

目录 引言 一&#xff0c;下载8.0数据库 二&#xff0c;下载5.6系列数据库 三&#xff0c;启动数据库 四&#xff0c;MySQL卸载 引言 The worlds most popular open source database&#xff1a;世界上最流行的开源数据库&#xff01; 一&#xff0c;下载8.0数据库 目前MySQ…

Spark-SortShuffle原理

总结: 每个Task会先把数据发送到缓冲区中&#xff0c;缓冲区满了会排序溢写到临时文件&#xff0c;等到Task计算完成之后&#xff0c;会把这些临时文件合并成一个大文件&#xff0c;和一个index文件&#xff0c;文件内容是有序的&#xff0c;等到所有的Task计算完成之后&#…

华为数通HCIA-华为VRP系统基础

什么是VRP? VRP是华为公司数据通信产品的通用操作系统平台&#xff0c;作为华为公司从低端到核心的全系列路由器、以太网交换机、业务网关等产品的软件核心引擎。 VRP提供以下功能&#xff1a; 实现统一的用户界面和管理界面 实现控制平面功能&#xff0c;并定义转发平面接口…

fork函数 创建子进程

fork&#xff1a; fork函数调用一次&#xff0c;返回两次&#xff1b;对于子进程&#xff0c;返回值0&#xff1b; 对于父进程&#xff0c;返回的是子进程的进程ID。 #include<iostream> #include<string.h> #include<sys/unistd.h> #include<syscall.h&…