让单链表不再云里雾里

一日不见,如三月兮!接下来与我一起创建单链表吧!

目录

单链表的结构:

创建单链表:

增加结点:

插入结点:

删除结点:

打印单链表:

单链表查找:

单链表指定位置插入:

单链表指定位置删除:

答疑解惑:

结语:


单链表的结构:

单链表有不带头单向不循环,和带头单向非循环两种类型,我们将探索的是不带头单向不循环的链表;它有两种结构:逻辑结构和物理结构,如下图:

因为物理结构便于理解,所以我们参照它来进行代码书写,物理结构中我们访问的都是地址,所以我们会使用指针,且蓝色所指表示它们两的地址相同!

创建单链表:

首先我们要定义一个结构体,然后我们要访问数值,所以会定义一个整型变量,为了找下一个数值的地址,我们还需创建一个指针

typedef int SLTDataType;
typedef struct SListNode
{
    SLTDataType data;
    struct SListNode* next;//方便查找下一个结点
}SLTNode;

增加结点:

因为每次插入,都需要书写一个代码,为了节省空间,我们将它包装成一个函数,方便我们进行调用

SLTNode* Buynewnode(SLDataType x)
{
    SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//开辟空间
    if(newnode == NULL)//判断是否开辟成功
    {
        perror("malloc fail");
        return;
    }
    newnode->data = x;//将数据赋值
    newnode->next = NULL;
    
    return newnode;//返回地址
}

插入结点:

头插:

首先将一开始头的数据地址赋给新的结点的下一个(newnode->next)地址,再将头指针变为新结点

void SLTPushFront(SLTNode** pphead,SLTDataType x)
{
    assert(pphead);
    SLTNode* newnode = Buynewnode(x);
    newnode->next = *pphead;
    *pphead = newnode;
}

尾插:

首先判断链表是否为空的情况,若为空,则将新结点赋给头结点即可,如果不是,再进行找尾,当找到尾时,将新结点的地址赋给tail的下一个。

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
    assert(pphead);
    SLTNode* newnode = Buynewnode(x);
    //判断是否为空
    if(*pphead == NULL)
    {
        *pphead = newnode;
    }
    else
    {
        //找尾
        while(tail->next != NULL)
        {
            tail = tail->next;
        }
        tail->next = newnode;//链接新结点
     }
}

删除结点:

头删:

先判断链表是否为空,若不为空,将第二个的数据地址赋给头指针即可,但我们怎么找到第二个的数据地址呢?我们可以先将头指针赋给一个指针进行保存,再将创建的指针找到其下一个的地址(即第二个数据的地址)赋给头指针,在释放第一个结点的地址即可。

void SLTPopFront(SLTNode** pphead)
{
    assert(pphead);
    assert(*pphead);
    SLTNode* begin = *pphead;//保存头指针
    *pphead = begin->next;
    free(begin)//释放第一个结点的空间
    begin = NULL;
}

尾删:

首先判断单链表是否为空,其次判断一下是否只有一个结点,若只有一个,直接将头指针释放置空即可,剩下的情况我们只要找到尾将它删除即可,有人想偷懒,将上面的找尾代码拷贝,然后将其置空,果真这么简单吗?会导致什么结果呢?又该怎么处理呢?

如果将tail置空,会使前一个结点的下一个指针变为野指针,tail置空是将局部变量置空,而非将结构体变量置空,若要改变这个情况,我们再定义一个结构体指针,找到tail的前面一个头结点,再将其下一个置空就行了

void SLTPopBack(SLTNode** pphead)
{
    //为空
    assert(pphead);
    assert(*pphead);
    //只有一个结点
    if((*pphead)->next == NULL)
    {
        free(*pphead);
        *pphead = NULL;
    }
    else
    {
        SLTNode* prev = NULL;
        SLTNode* tail = *pphead;
        //找尾
        while(tail->next != NULL)
        {
            prev = tail;//找到tail前一个结点
            tail = tail->next;
        }
        //释放掉尾结点
        free(tail)
        tail = NULL;
        prev->next = NULL;
    }
}

打印单链表:

将头指针赋值给一个指针变量,这样可以防止头指针被覆盖(这个作用这里体现不明显),然后循环遍历就OK了

void SLTPrint(SLTNode* phead)
{
    SLTNode* begin = phead;
    //循环遍历
    while(begin)
    {
        printf("%d->", begin->data);
        begin = begin->next;
    }
    printf("NULL\n");
}

单链表查找:

将头指针赋值给一个指针变量,然后遍历,用if语句判断

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
    SLTNode* cur = phead;
    while(cur)
    {
        if(cur->data == x)
        {
            //找到返回
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

单链表指定位置插入:

我们先定义一个指针变量,用来找我们指定插入的位置地址,找到这个指针变量的前一个位置的地址,再将新结点的地址赋给前一个的下一个地址(next),再将指针变量赋给新节结点的下一个地址

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
    assert(pos);//判断pos是否为空
    assert(pphead);
    SLTNode* newnode = Buynewnode(x);
    if(*pphead == pos)
    {
        newnode->next = pos;
        *pphead = newnode//将新结点赋给头指针
    }
    else
    {
        SLTNode* prev = *pphead;
        //找到pos前面一个地址
        while(prev->next != pos)
        {
            prev = prev->next;
        }
        prev->next = newnode;
        newnode->next = pos;
     }
}

单链表指定位置删除:

我们先定义一个指针变量,用来找我们指定插入的位置地址,找到这个指针变量的前一个位置的地址,再将指定位置的下一个,赋给前一个位置的下一个,再将指定位置释放置空

void SLTErase(SLTNode** pphead, SLTNode* pos)
{
    assert(pos);//判断pos是否为空
    assert(pphead);
    //只有一个结点
    if(*pphead == pos)
    {
        *pphead = pos->next;
         free(pos);
         pos = NULL;
    }
    else
    {
        SLTNode* prev = *pphead;
        //找pos前一个位置
        while(prev->next != pos)
        {
            prev = prev->next;
        }
        prev->next = pos->next;
        free(pos);//释放指定位置空间
        pos = NULL;
     }
}

答疑解惑:

为什么要传二级指针? 因为要修改结构体指针,所以要用二级指针,比如修改变量,用一级指针修改才行!

什么时候用assert?当一个变量一定不为空时,则用assert,比如插入数据时,*pphead可以为空,所以不用断言,亦或者打印时,也可以打印空数据,所以也不用断言。

结语:

谢谢大家观看!期待下次见面哦!

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

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

相关文章

图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image

图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image 文章目录 图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image主要创新点模型架构图生成器生成器源码 判别器判别器源码 损失函数需要源码讲解的私信我 S…

指纹细节提取(Matlab实现)

指纹细节提取概述指纹作为人体生物特征识别领域中应用最为广泛的特征之一,具有独特性、稳定性和便利性。指纹细节特征对于指纹识别的准确性和可靠性起着关键作用。指纹细节提取,即从指纹图像中精确地提取出能够表征指纹唯一性的关键特征点,是…

泵吸式激光可燃气体监测仪:快速精准守护燃气管网安全

在城市化进程加速的今天,燃气泄漏、地下管网老化等问题时刻威胁着城市安全。如何实现精准、高效的可燃气体监测,守护“城市生命线”,成为新型基础设施建设的核心课题。泵吸式激光可燃气体监测仪,以创新科技赋能安全监测&#xff0…

HTML label 标签使用

点击 <label> 标签通常会使与之关联的表单控件获得焦点或被激活。 通过正确使用 <label> 标签&#xff0c;可以使表单更加友好和易于使用&#xff0c;同时提高整体的可访问性。 基本用法 <label> 标签通过 for 属性与 id 为 username 的 <input> 元素…

数字万用表的使用教程

福禄克经济型数字万用表前面板按键功能介绍示意图 1. 万用表简单介绍 万用表是一种带有整流器的、可以测量交、直流电流、电压及电阻等多种电学参量的磁电式仪表。分为数字万用表&#xff0c;钳形万用表&#xff0c; &#xff08;1&#xff09;表笔分为红、黑二只。使用时黑色…

Python 爬取唐诗宋词三百首

你可以使用 requests 和 BeautifulSoup 来爬取《唐诗三百首》和《宋词三百首》的数据。以下是一个基本的 Python 爬虫示例&#xff0c;它从 中华诗词网 或类似的网站获取数据并保存为 JSON 文件。 import requests from bs4 import BeautifulSoup import json import time# 爬取…

2025年AI PPT工具精选:让演示文稿更智能、更高效

&#x1f4a1; 做PPT太难&#xff1f;没灵感&#xff1f;排版不好看&#xff1f;别怕&#xff0c;AI已经帮你安排好了&#xff01; 想知道2025年最值得推荐的AI PPT工具是哪款&#xff1f;答案就是——秒出PPT&#xff01;&#x1f680; 不仅能一键生成PPT&#xff0c;还能自…

qt-C++笔记之ubuntu22.04源码安装Qt6.8.2

qt-C笔记之ubuntu22.04源码安装Qt6.8.2 code review! 文章目录 qt-C笔记之ubuntu22.04源码安装Qt6.8.21.作者环境&#xff1a;ubuntu22.04、cmake202.安装3.关联已安装的 Qt6 到 Qt Creator4.附&#xff1a;ubuntu18.0的处理&#xff0c;可尝试&#xff0c;作者没有遇到这个问题…

单例模式(线程案例)

单例模式可以分为两种&#xff1a;1.饿汉模式 2.懒汉模式 一.饿汉模式 //饿汉模式&#x1f447; class MySingleTon{//因为这是一个静态成员变量&#xff0c;在类加载的时候&#xff0c;就创建了private static MySingleTon mySingleTon new MySingleTon();//创建一个静…

基于Matlab的多目标粒子群优化

在复杂系统的设计、决策与优化问题中&#xff0c;常常需要同时兼顾多个相互冲突的目标&#xff0c;多目标粒子群优化&#xff08;MOPSO&#xff09;算法应运而生&#xff0c;作为群体智能优化算法家族中的重要成员&#xff0c;它为解决此类棘手难题提供了高效且富有创新性的解决…

(2025年)工会考试该如何高效备考?有学习方法吗?

工会考试备考文章 工会考试高效备考指南 工会在维护职工权益、促进企业和谐发展中扮演着重要角色&#xff0c;工会考试则是选拔优秀工会工作者的关键途径。面对工会考试涉及的法律法规、组织管理以及维权服务等多方面知识&#xff0c;掌握科学备考方法是成功的关键。 法律法规是…

《机器学习数学基础》补充资料:向量范数

《机器学习数学基础》第1章1.5.3节介绍了向量范数的基本定义。 本文在上述基础上&#xff0c;介绍向量范数的有关性质。 注意&#xff1a; 以下均在欧几里得空间讨论&#xff0c;即欧氏范数。 1. 性质 实&#xff08;或复&#xff09;向量 x \pmb{x} x &#xff0c;范数 ∥…

Unity NGUI新手向几个问题记录

1.点Button没反应 制作Button组件时&#xff0c;不光要挂载Button脚本&#xff0c;还有挂载BoxCollider BoxCollider 接收事件 2.Button点击事件的增加与删除 使用.onClick.add增加事件&#xff0c;使用.onClick.Remove,.onClick.RemoveAt,onClick.RemoveRang,onClick.Clear移…

servlet tomcat

在spring-mvc demo程序运行到DispatcherServlet的mvc处理 一文中&#xff0c;我们实践了浏览器输入一个请求&#xff0c;然后到SpringMvc的DispatcherServlet处理的整个流程. 设计上这些都是tomcat servlet的处理 那么究竟这是怎么到DispatcherServlet处理的&#xff0c;本文将…

UniApp 中封装 HTTP 请求与 Token 管理(附Demo)

目录 1. 基本知识2. Demo3. 拓展 1. 基本知识 从实战代码中学习&#xff0c;上述实战代码来源&#xff1a;芋道源码/yudao-mall-uniapp 该代码中&#xff0c;通过自定义 request 函数对 HTTP 请求进行了统一管理&#xff0c;并且结合了 Token 认证机制 请求封装原理&#xff…

【音视频】ffmpeg命令分类查询

一、ffmpeg命令分类查询 -version&#xff1a;显示版本 ffmpeg -version-buildconf&#xff1a;显示编译配置&#xff0c;这里指的是你编译好的ffmpeg的选项 ffmpeg -buildconf-formats:显示可用格式&#xff08;muxersdemuxers&#xff09;&#xff0c;复用器和解复用器&am…

基于Windows11的DockerDesktop安装和布署方法简介

基于Windows11的DockerDesktop安装和布署方法简介 一、下载安装Docker docker 下载地址 https://www.docker.com/ Download Docker Desktop 选择Download for Winodws AMD64下载Docker Desktop Installer.exe 双点击 Docker Desktop Installer.exe 进行安装 测试Docker安装是…

C++发展

目录 ​编辑C 的发展总结&#xff1a;​编辑 1. C 的早期发展&#xff08;1979-1985&#xff09; 2. C 标准化过程&#xff08;1985-1998&#xff09; 3. C 标准演化&#xff08;2003-2011&#xff09; 4. C11&#xff08;2011年&#xff09; 5. C14&#xff08;2014年&a…

爬虫Incapsula reese84加密案例:Etihad航空

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关 一、找出需要加密的参数 1.js运行 atob(‘aHR0cHM6Ly93d3cuZXRpaGFkLmNvbS96aC1jbi8=’) 拿到网址,F12打开调试工具,随便搜索航班,切换到network搜索一个时间点可以找…

【分享】网间数据摆渡系统,如何打破传输瓶颈,实现安全流转?

在数字化浪潮中&#xff0c;企业对数据安全愈发重视&#xff0c;网络隔离成为保护核心数据的重要手段。内外网隔离、办公网与研发网隔离等措施&#xff0c;虽为数据筑牢了防线&#xff0c;却也给数据传输带来了诸多难题。传统的数据传输方式在安全性、效率、管理等方面暴露出明…