数据结构——单链表详解(超详细)(2)

前言:

  上一篇文章小编简单的介绍了单链表的概念和一些函数的实现,不过为了保证文章的简洁,小编把它分成了两篇来写,这一篇小编紧接上一篇文章继续写单链表函数功能的实现:

目录:

1.单链表剩余函数的编写

1.1.单链表查找数据

1.2.在指定位置之前插入数据

1.3.删除指定结点

1.4.在指定位置之后插入数据

1.5.删除指定位置之后的结点

1.6.单链表的销毁

2.完整的代码呈现

正文:

1.单链表剩余函数的编写

1.1.单链表查找数据

//查找SLTNode* SLTFind(SLTNode* phead, SLdate x);

  对于单链表的查找数据,这就类似顺序表的查找数据,我们要遍历所有的单链表,直到找到我们想要的数据位置,加入没有我们想要的数据,那么我们可以直接返回一个空地址就好了,此时我们不必再传单链表指针的地址了,因为我们本质上并没有对头结点进行改变 ,所以我们仅需把头节点传过去就可以,在函数内部,我们想要遍历顺序表,就要采用循环,来进行一个一个结点的查找,下面是代码呈现:

SLTNode* SLTFind(SLTNode* phead, SLdate x)
{SLTNode* pour = phead;while (pour){if (pour->date == x){return pour;}pour = pour->next;}return NULL;
}

 1.2.在指定位置之前插入数据

    这里我们可以用到我们上面用到的查找函数,因为它是返回的结点,所以我们可以通过它来确定我们想要的指定位置,因为单链表只可以往后一步一步的走,而不能往前找数据,所以我们得先确认我们想要找的位置,下面我们涉及指定位置的时候,都要引用一下查找指定位置这个函数,下面我们来进行这个函数的讲解,这个函数其实也分为两种情况

  第一种情况是指定位置就是头结点,此时这就类似于我们之前写过的头插函数,我们直接引用头插函数就可以实现这个功能。

  第二种情况就是普通情况,我们要在指定位置之前插入数据,所以我们需要找到指定位置之前的数据,所以这里我们要用用到头结点,并且用到前面讲的创建新结点的函数(因为此文章涉及了不少插入数据的函数,所以我会把创建新结点的代码再写一遍!),我们让一个结点放入头结点数据,然后一步一步往后走,直到走到指定位置之前,之后我们可以讲新节点的下一个结点设置为指定结点,然后再把之前指定位置之前的结点的下一个结点设置为新结点,这里我们便可以完成在指定位置之后插入数据,下面小编先给上图文解释:

新结点的创建:

SLTNode* SLTbuynode(SLdate x)
{SLTNode* pour = (SLTNode*)malloc(sizeof(SLTNode));assert(pour);pour->date = x;pour->next = NULL;return pour;
}

头插函数: 

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

函数部分:

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLdate x)
{assert(pos && pphead && *pphead);if (pos == *pphead){SLTPushFront(pphead,x);   //这个是头节点就是pos的特殊情况,我们在指定位置之前插入数据的时候,是会先找到指定位置之前的数据以及之后的,头节点的话找不到数据了}else{SLTNode* newnode = SLTbuynode(x);SLTNode* pour = *pphead;SLTNode* pur = NULL;while (pour != pos){pur = pour;pour = pour->next;}assert(pur);newnode->next = pour;pur->next = newnode;}

1.3.删除指定结点

  删除指定结点的操作,同样也和上面的函数一样,我们也分为两种情况进行讨论:

  第一种情况就是我们想要删除的指定节点就是头结点,此时我们只需要调用一下头删函数就可以实现。

  第二种情况自然就是普通情况,此时我们依旧需要用到头结点,因为我们需要知道指定结点之前的结点,之后我们只需要让前一个结点的下一个结点直接指向指定结点的下一个结点,之后我们在把指定节点给释放掉,就可以实现指定节点删除操作,下面小编先给上图文解释:

头删函数:

void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pour = *pphead;*pphead = (*pphead)->next;free(pour);pour = NULL;
}

删除指定结点函数:

void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead && pos <= *pphead);if (*pphead == pos){SLTPopFront(pphead);}else{SLTNode* pour = *pphead;SLTNode* pur = NULL;while (pour != pos){pur = pour;pour = pour->next;}assert(pur);pur -> next = pur->next -> next;free(pour);pour = NULL;}
}

1.4.在指定位置之后插入数据

  小编在上面已经讲述了指定位置之前如何插入数据了,那么现在可以讲述在指定位置之后插入数据了,这个其实比上面那个简单多了,因为此时我们不需要用到指定位置之前的结点了,所以我们不必在使用头结点了,此时我们依然需要先创建一个新节点,之后我们在讲新结点之后的结点变为我们指定位置之后的结点,指定位置之后的结点·在指向新节点,这里就可以实现在指定位置之后插入新数据了,下面小编先给上图文解释,再给上代码呈现: 

  

void SLTInsertAfter(SLTNode* pos, SLdate x)
{assert(pos);SLTNode* newnode = SLTbuynode(x);newnode->next = pos->next;pos->next = newnode;
}

1.5.删除指定位置之后的结点

  有插入必会有删除,下面我们将要讲述最后一个重要的函数,那么就是删除指定位置之后的结点,这个,同样也是非常的简单,我们只需要把指定结点的下一个结点变为下一个的下一个的结点,再把原来指定位置之后的结点释放掉就好了,下面我们直接给出图像说明:

void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* pour = pos -> next;pos->next = pos->next->next;free(pour);pour = NULL;
}

1.6.单链表的销毁

  单链表有创建,自然就会有销毁,单链表的销毁也不算很难,毕竟难的部分都在上面,轻舟已过万重山,对于单链表的销毁其实就是把每个结点给free掉,我们可以设置一个指针作为头结点,在设置一个指针用来给予上一个指针,每销毁完一个结点,我们把第二个指针的内容给予第一个指针,然后让第二个指针继续往后走,这样我们通过循环的知识可以做到每个结点的删除,循环结束完以后,别忘了对头结点进行销毁,这样我们便可以完成对于单链表的销毁了,下面直接给上代码:

void SListDestroy(SLTNode** pphead)
{assert(*pphead && pphead);SLTNode* pour = *pphead;while (pour){SLTNode* next = pour->next;free(pour);pour = next;}*pphead = NULL;
}

2.完整的代码呈现

  现在,小编已经把单链表大部分内容给讲完了,但单链表实现的功能远不止这些,感兴趣的读者朋友可以再继续探索,小编这里给上大家单链表的完整代码:

SList.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLdate;   //方便后面整体类型的改变//创立一个单链表
typedef struct Slist {//先设置一个类型SLdate date;struct Slist* next;   //存放下一个节点的地址
}SLTNode;//链表的打印
void SLTprintf(SLTNode* phead);//开始正式环节了
//尾插
void SLTPushBack(SLTNode** pphead, SLdate x);//头插
void SLTPushFront(SLTNode** pphead, SLdate x);//尾删
void SLTPopBack(SLTNode** pphead);//头删void SLTPopFront(SLTNode** pphead);//查找SLTNode* SLTFind(SLTNode* phead, SLdate x);//在指定位置之前插入数据void SLTInsert(SLTNode** pphead, SLTNode* pos, SLdate x);//删除pos节点void SLTErase(SLTNode** pphead, SLTNode* pos);//在指定位置以后插入数据void SLTInsertAfter(SLTNode* pos, SLdate x);//删除pos之后的节点void SLTEraseAfter(SLTNode* pos);//销毁链表
void SListDestroy(SLTNode** pphead);

SList.c

#include"SList.h"
void SLTprintf(SLTNode* phead)
{SLTNode* pour = phead;    //这么做是为了保证头节点不会发生改变while (pour){printf("%d->", pour->date);pour = pour->next;}printf("NULL\n");
}   //这个操作是打印单链表的数据SLTNode* SLTbuynode(SLdate x)
{SLTNode* pour = (SLTNode*)malloc(sizeof(SLTNode));assert(pour);pour->date = x;pour->next = NULL;return pour;
}void SLTPushBack(SLTNode** pphead, SLdate x)
{//首先可以先建一个函数,这个函数是来开辟一个新节点的(后面想要插入直接调用就好了)assert(pphead);SLTNode * p = SLTbuynode(x);if (*pphead == NULL)  //首先判断{*pphead = p;}else{SLTNode* pour = *pphead;while (pour -> next){pour = pour->next;}pour->next = p;}
}void SLTPushFront(SLTNode** pphead, SLdate x)
{assert(pphead);SLTNode* newnode = SLTbuynode(x);newnode->next = *pphead;*pphead = newnode;
}void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);if ((*pphead)->next == NULL){*pphead = NULL;}else{SLTNode* pour = *pphead;SLTNode* plist = NULL;while (pour->next){plist = pour;pour = pour->next;}plist->next = NULL;free(pour);pour = NULL;}
}void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pour = *pphead;*pphead = (*pphead)->next;free(pour);pour = NULL;
}SLTNode* SLTFind(SLTNode* phead, SLdate x)
{SLTNode* pour = phead;while (pour){if (pour->date == x){return pour;}pour = pour->next;}return NULL;
}void SLTInsert(SLTNode** pphead, SLTNode* pos, SLdate x)
{assert(pos && pphead && *pphead);if (pos == *pphead){SLTPushFront(pphead,x);   //这个是头节点就是pos的特殊情况,我们在指定位置之前插入数据的时候,是会先找到指定位置之前的数据以及之后的,头节点的话找不到数据了}else{SLTNode* newnode = SLTbuynode(x);SLTNode* pour = *pphead;SLTNode* pur = NULL;while (pour != pos){pur = pour;pour = pour->next;}assert(pur);newnode->next = pour;pur->next = newnode;}
}void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead && pos <= *pphead);if (*pphead == pos){SLTPopFront(pphead);}else{SLTNode* pour = *pphead;SLTNode* pur = NULL;while (pour != pos){pur = pour;pour = pour->next;}assert(pur);pur -> next = pur->next -> next;free(pour);pour = NULL;}
}void SLTInsertAfter(SLTNode* pos, SLdate x)
{assert(pos);SLTNode* newnode = SLTbuynode(x);newnode->next = pos->next;pos->next = newnode;
}void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* pour = pos -> next;pos->next = pos->next->next;free(pour);pour = NULL;
}void SListDestroy(SLTNode** pphead)
{assert(*pphead && pphead);SLTNode* pour = *pphead;while (pour){SLTNode* next = pour->next;free(pour);pour = next;}*pphead = NULL;
}

总结:

  可算快马加鞭的肝完这篇文章了,小编本来想上一篇文章就结束单链表的,但是觉得万字文章有点太多了内容,于是分装成两篇来书写,因为小编是学完了单链表就开始写的文章,有一些地方可能有错误或者文笔显得很繁琐,各位读者朋友见谅,如果有错误的话,恳请在评论区指出,小编会及时的更正,那么,我们下一篇文章见啦! 

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

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

相关文章

Lua 运算符

Lua 运算符 Lua 是一种轻量级的编程语言&#xff0c;广泛用于游戏开发、脚本编写和其他应用程序。它具有一套丰富的运算符&#xff0c;用于执行各种数学和逻辑操作。本文将详细介绍 Lua 中的运算符&#xff0c;包括算术运算符、关系运算符、逻辑运算符和其他特殊运算符。 算术…

高级java每日一道面试题-2024年7月17日

面试官: java中都有哪些引用类型? 我回答: 强引用&#xff08;Strong Reference&#xff09; 描述&#xff1a;这是最常见和最直观的引用类型&#xff0c;我们通常在代码中创建的对象引用就是强引用。例如&#xff0c;Object obj new Object();。只要强引用存在&#xff0c;…

Idea如何快速高效的修改项目的包名

文章目录 前言一、全局替换的快捷键二、弹出如下的界面 前言 当我们有时候在做项目迁移的时候&#xff0c;需要快速的修改项目的包名&#xff01;那么如何快速高效的修改项目的报名呢&#xff1f; 经过尝试了很多方法&#xff01;最简单的方法就是利用全局替换来直接替换报名&…

微服务到底是个什么东东?

微服务架构是一种架构模式&#xff0c;它提倡将单一应用程序划分成一组小的服务&#xff0c;服务之间互相协调、互相配合&#xff0c;为用户提供最终价值。 每个服务运行在其独立的进程中&#xff0c;服务和服务间采用轻量级的通信机制互相沟通&#xff08;通常是基于 HTTP 的…

通过反射机制给已知属性赋值

最近在看spring&#xff0c;在手写spring框架之前&#xff0c;需要巩固一下反射。 反射有这样一个简单的例子&#xff0c;记录一下。 假如你知道age这个属性名&#xff0c;但是不知道属性类型&#xff0c;也可以写&#xff1a; 可以获取到属性的类型

昇思25天学习打卡营第11天 | mindspore 实现 ResNet 50 迁移学习

1. 背景&#xff1a; 使用 mindspore 学习神经网络&#xff0c;打卡第 11 天&#xff1b;主要内容也依据 mindspore 的学习记录。 2. 迁移学习介绍&#xff1a; mindspore 实现 ResNet 50 迁移学习&#xff1b; 具体 ResNet 50 的模型原理以及实现&#xff0c;可以参考本博客…

谈谈我对李彦宏说的“不要卷模型,要卷应用”的理解

我理解李彦宏的发言是强调人工智能技术应该关注应用而不是仅仅关注模型的发展。他认为AI技术已经从辨别式&#xff08;discriminative&#xff09;转向了生成式&#xff08;generative&#xff09;&#xff0c;意味着AI不再仅仅是识别和分类问题&#xff0c;而是能够创造新的内…

设计模式-领域逻辑模式-事务脚本(Transaction Script)

事务脚本的特点 多数应用可看成由多个事务组成事务脚本将多个业务逻辑组织成单个过程事务间相互修改各自产生的数据 事务脚本的运行机制 使用事务脚本时&#xff0c;领域逻辑主要通过系统所执行的事务来组织。例如&#xff1a;预定酒店过程。 事务脚本的组织 将整个事务脚本放…

【BUG】已解决:IndexError: list index out of range

已解决&#xff1a;IndexError: list index out of range 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区…

微信小程序:2.全局开发

app实例 简介 app.js中注册小程序实例的方法App拥有生命周期回调函数、错误监听函数、页面不存在监听函数等 生命周期回调函数 onLaunch(options) {//监听小程序初始化 console.log("监听小程序初始化",options); }, onShow (options) {//监听小程序启动或切前台…

Ubuntu串口调试单片机

来自🥬🐶程序员 Truraly | 田园 的博客,最新文章首发于:田园幻想乡 | 原文链接 | github (欢迎关注) 文章目录 brltty 导致 USB 转串口连接失败串口调试工具直接操作串口puttySerial Monitor | vscode 插件minicom(推荐)舍友在搞 c-sky 的单片机,囚来了一块玩玩,尝…

【C++】C++中的getcwd函数详解

目录 一.getcwd函数是什么 二.getcwd函数怎么用 一.getcwd函数是什么 在C中&#xff0c; getcwd 是一个用于获取当前工作目录的函数&#xff0c;它是POSIX标准的一部分&#xff0c;定义在 <unistd.h> 头文件中&#xff08;在Windows上&#xff0c;它定义在 <direct…

对服务器进行基本了解(二)

目录 一. 云服务器数据库 1.查看MYSQL版本 2.查看mysql的运行状态 3.运行mysql 4. 进入mysql的用户 5. 更改用户密码 6. 查找mysql端口号 7. 创建一个数据库 8. 查看用户 9. 查看数据库 10. 显示数据库的表 11. 修改用户的host 12. 对用户赋权 13. 开放指定端…

python程序设定定时任务

在 Windows 系统上,您可以使用任务计划程序(Task Scheduler)来设置定时任务,执行 Python 文件。以下是具体步骤: 步骤 1:准备 Python 文件 假设有一个名为 script.py 的 Python 脚本。确保它可以在命令行中正确运行。 步骤2:找到Python可执行文件的位置 知道Python可…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(一)-3GPP TS 23.256 技术规范概述

3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 以下是文档的核心内容总结&#xff1a; UAV系…

nginx的access.log日志输出请求数

适用格式 #log_format main $remote_addr - $remote_user [$time_local] "$request" # $status $body_bytes_sent "$http_referer" # "$http_user_agent" "$http_x_forwarded_for"; 形如&#…

自然语言处理中的本体/分类/同义相似

本体相似、分类相似与同义相似这三个概念都是在信息检索和自然语言处理中经常用到的相似性度量方法&#xff0c;它们的区别如下&#xff1a; 本体相似&#xff1a;本体是领域内的概念及其关系的模型&#xff0c;本体相似性度量是指计算两个本体之间的相似程度。本体相似性度量通…

【JVM实战篇】内存调优:内存问题诊断+案例实战

文章目录 诊断内存快照在内存溢出时生成内存快照MAT分析内存快照MAT内存泄漏检测的原理支配树介绍如何在不内存溢出情况下生成堆内存快照&#xff1f;MAT查看支配树MAT如何根据支配树发现内存泄漏 运行程序的内存快照导出和分析快照**大文件的处理** 案例实战案例1&#xff1a;…

CH390H+STM32F1+LWIP

文章目录 1、CH390芯片介绍2、电路部分3、LWIP调试3.1修改点13.2 修改点2 4、结果展示参考 1、CH390芯片介绍 官网地址&#xff1a; 南京沁恒微电子股份有限公司 特点&#xff1a; 2、电路部分 CH390及接口&#xff1a; STM32F1引脚&#xff1a; 不含LWIP的demo及LWIP…

【WPF】图片剪裁-ImageCropping

【WPF】图片剪裁-ImageCropping 背景技术栈实现思路核心代码界面布局Style处理逻辑使用技巧预览下载背景 机缘巧合吧,当时在全网寻找图像剪裁工具,但大都不能满足需求,于是决定动手写。当然如果只是为了完成这么一个功能就没有必要记录了,主要是不依赖与第三方图像库,且实…