哲学家带你实现单链表

2024-04-12 19:52
文章标签 实现 单链 哲学家

本文主要是介绍哲学家带你实现单链表,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近本哲♂学家学习了链表这一新的数据结构,接下来由我带领大家实现链表:

一 、头文件

注:本写法是无头的单链表,所以传参为二级指针。

我们事先写好所要完成的函数,在 .c文件中进一步去完成。

typedef int SLTDataType;
typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SLTNode;//创建新节点
SLTNode* SLTBuyNode(SLTDataType x);
//打印节点
void SLTPrint(SLTNode* phead);//头部插入删除/尾部插入删除
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);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);

二、.C文件

1、创建新的节点

链表与顺序表不同,不需要扩容空间,所以直接用malloc即可。

SLTNode* SLTBuyNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL)//如果开辟失败,直接退出{perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;return newnode;
}

2、打印链表

链表是由每一个节点里面的next指针指向的下一个节点的地址联系起来的,所以我们可以通过对next的访问来实现访问链表。

oid SLTPrint(SLTNode* phead)
{assert(phead);//不能对空指针解引用SLTNode* prive = phead;while (prive != NULL){printf("%d->", prive->data);prive = prive->next;}printf("NULL");
}

3、尾插和尾删

1、尾插

如果该链表没有节点(phead默认为NULL),则我们通过对phead解引用访问next程序会崩溃,所以我们要对上面的情况单独考虑,如果有节点,我们让第一个节点的next指向下一个节点的地址即可。

void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);if (*pphead == NULL)//我们创建时只创建了头节点的地址,所以如果传一级指针这就无法实现尾插,后面的更是执行不到{*pphead = newnode;}else{//找到尾部SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}ptail->next = newnode;}
}
//void MYSLTPushBack(SLTNode* pphead, SLTDataType x)

注意我们创建时只创建了头节点的地址,所以如果传一级指针就无法实现没有节点情况下的尾插,后面的尾插更是执行不到。所以要传二级指针。

2、尾删

一般思路时找到链表尾节点将尾节点释放,前一个节点的next为NULL;但是如果为一个节点上面思路并不能满足我们要达到的效果,所以要对只有一个节点的情况单独考虑。

void SLTPopBack(SLTNode** pphead)
{assert(pphead && *pphead);//链表不能为空//只有一个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{//找到尾部的前一个节点SLTNode* ptail = *pphead;SLTNode* pptail = *pphead;while (ptail->next){pptail = ptail;ptail = ptail->next;}pptail->next = NULL;//这已经把尾节点前的一个节点和尾节点找到了,不用考虑先将哪个置为空free(ptail);ptail = NULL;}}

4、头插和头删

1、头插

按照前面尾插的思路,我们知道得分为只有一个节点,和有多个节点的情况,所以我们很容易写出下面的代码:

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);//如果只有头节点且为nullif (*pphead == NULL){*pphead = newnode;}else{newnode->next = (*pphead);(*pphead) = newnode;}
}

但是事实上要不要这么麻烦呢?

实际上将只有一个节点的情况带入第二种情况中发现也是可行的所以代码可以简化如下:

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

2、头删

同样的我们根据前面尾删的思路可以知道要分为两种情况,但事实上,不需要那么麻烦,不用考虑只有一个节点的情况。

void SLTPopFront(SLTNode** pphead)
{//链表不能为空assert(pphead && *pphead);SLTNode* next = (*pphead)->next; //-> 优先级高于*free(*pphead);*pphead = next;
}

5、查找

只要遍历所以链表找到匹配的链表的地址返回就可以了

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{SLTNode* pcur = phead;while (pcur)//等价于pcur != NULL{if (pcur->data == x){return pcur;}pcur = pcur->next;}//pcur == NULLreturn NULL;
}

6、指定位置前添加节点和删除指定位置节点

1、指定位置前添加

这里我们需要考虑特殊情况:就是当链表只有一个元素时,相当于变成了头插,其他情况时我们要找到pos的前一个节点,所以我们可以写出如下代码:

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);//*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的next指针指向pos是prev为前一个节点{prev = prev->next;}//prev -> newnode -> posnewnode->next = pos;prev->next = newnode;}
}

2、删除指定位置节点

同样的如果pos为头节点,则为头删:

void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);//pos是头结点/pos不是头结点if (pos == *pphead){//头删SLTPopFront(pphead);}else {SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//prev pos pos->nextprev->next = pos->next;free(pos);pos = NULL;}
}

7、指定位置后添加和删除节点

1、指定位置后添加

这里我们还要考虑其为尾结点的情况:

void SLTInsertAfter(SLTNode* pos, SLTDataType x, SLTNode** pphead)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);if (pos->next == NULL){SLTPushBack(pphead,x);}else{SLTNode* aft = pos->next;newnode->next = aft;pos->next = newnode;}
}

2、指定位置之后删除

同理我们也得考虑其为尾节点的情况:

void SLTEraseAfter(SLTNode* pos, SLTNode** pphead)
{assert(pos);//SLTNode* newnode = SLTBuyNode(x);if (pos->next == NULL){SLTPopBack(pphead);}else{SLTNode* del = pos->next;//pos del del->nextpos->next = del->next;free(del);del = NULL;}
}

8、销毁链表

void SListDesTroy(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}//pcur*pphead = NULL;
}

总结:

链表相对于顺序表来说更好实现,但比较难的是理解其是如何实现将各个节点连起来的。期待下一次我们一起van♂。

这篇关于哲学家带你实现单链表的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根

SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程

《SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程》LiteFlow是一款专注于逻辑驱动流程编排的轻量级框架,它以组件化方式快速构建和执行业务流程,有效解耦复杂业务逻辑,下面给大... 目录一、基础概念1.1 组件(Component)1.2 规则(Rule)1.3 上下文(Conte

MySQL 横向衍生表(Lateral Derived Tables)的实现

《MySQL横向衍生表(LateralDerivedTables)的实现》横向衍生表适用于在需要通过子查询获取中间结果集的场景,相对于普通衍生表,横向衍生表可以引用在其之前出现过的表名,本文就来... 目录一、横向衍生表用法示例1.1 用法示例1.2 使用建议前面我们介绍过mysql中的衍生表(From子句

Mybatis的分页实现方式

《Mybatis的分页实现方式》MyBatis的分页实现方式主要有以下几种,每种方式适用于不同的场景,且在性能、灵活性和代码侵入性上有所差异,对Mybatis的分页实现方式感兴趣的朋友一起看看吧... 目录​1. 原生 SQL 分页(物理分页)​​2. RowBounds 分页(逻辑分页)​​3. Page

Python基于微信OCR引擎实现高效图片文字识别

《Python基于微信OCR引擎实现高效图片文字识别》这篇文章主要为大家详细介绍了一款基于微信OCR引擎的图片文字识别桌面应用开发全过程,可以实现从图片拖拽识别到文字提取,感兴趣的小伙伴可以跟随小编一... 目录一、项目概述1.1 开发背景1.2 技术选型1.3 核心优势二、功能详解2.1 核心功能模块2.

MYSQL查询结果实现发送给客户端

《MYSQL查询结果实现发送给客户端》:本文主要介绍MYSQL查询结果实现发送给客户端方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql取数据和发数据的流程(边读边发)Sending to clientSending DataLRU(Least Rec

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

使用SpringBoot整合Sharding Sphere实现数据脱敏的示例

《使用SpringBoot整合ShardingSphere实现数据脱敏的示例》ApacheShardingSphere数据脱敏模块,通过SQL拦截与改写实现敏感信息加密存储,解决手动处理繁琐及系统改... 目录痛点一:痛点二:脱敏配置Quick Start——Spring 显示配置:1.引入依赖2.创建脱敏

基于Python实现一个简单的题库与在线考试系统

《基于Python实现一个简单的题库与在线考试系统》在当今信息化教育时代,在线学习与考试系统已成为教育技术领域的重要组成部分,本文就来介绍一下如何使用Python和PyQt5框架开发一个名为白泽题库系... 目录概述功能特点界面展示系统架构设计类结构图Excel题库填写格式模板题库题目填写格式表核心数据结构

C#之List集合去重复对象的实现方法

《C#之List集合去重复对象的实现方法》:本文主要介绍C#之List集合去重复对象的实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C# List集合去重复对象方法1、测试数据2、测试数据3、知识点补充总结C# List集合去重复对象方法1、测试数据