【数据结构】-- 单链表 vs 双向链表

🌈 个人主页:白子寰
🔥 分类专栏:python从入门到精通,魔法指针,进阶C++,C语言,C语言题集,C语言实现游戏👈 希望得到您的订阅和支持~
💡 坚持创作博文(平均质量分82+),分享更多关于深度学习、C/C++,python领域的优质内容!(希望得到您的关注~) 

目录

 单链表和双向链表的比较

链表的打印

单链表

双向链表 

初始化

双向链表

开辟空间,写入新数据

单链表

双向链表

尾部插入数据

单链表

双向链表

头部插入数据

单链表 

双向链表

尾部删除数据

单链表

双向链表

头部删除数据

单链表

双向链表

查找

单链表 

双向链表 

在指定位置之前插入数据 

单链表

在指定位置之后插入数据

单链表

双向链表 

 删除指定位置数据

单链表

双向链表

删除指定位置后的数据

单链表

销毁链表

单链表

双向链表


 单链表和双向链表的比较

单向链表双向链表
指代不同链表的链接方向是单向的,访问链表时时要顺序读取从头开始访问每个数据的节点都有两个指针,即直接前驱和直接后驱
优点不同单个节点创建方便,普通的线性内存通常在创建的时候就需要设定数据的大小,节点的访问方便,可以通过循环/递归的方法访问到任意数据从双向链表中的任意一个节点开始,方便访问前驱节点和后继节点
缺点不同增加/删除节点复杂,需要多分配一个指针存储空间平均访问效率低于线性表,只能从头到尾遍历,只能找到后继,无法找到前驱(只能前进)

链表的打印

单链表

//链表的打印
void SLTPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL\n");
}

双向链表 

//打印
void LTPrint(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){printf("%d->", pcur->dada);pcur = pcur->next;}printf("\n");
}

初始化

双向链表

//双向链表初始化
LTNode* LTInit()
{//哨兵位设置为-1LTNode* phead = SLTBuyNode(-1);return phead;
}

开辟空间,写入新数据

单链表

//开辟空间,写入新数据
SLTNode* SLTbuyNode(SLTDatatype x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc");exit(1);}//先插入,后数据为空(后为空)newnode->data = x;newnode->next = NULL;return newnode;//返回数据
}

双向链表

//扩容,申请新节点
LTNode* SLTBuyNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));//扩容if (newnode == NULL){perror("malloc");exit(1);}//数据赋值newnode->dada = x;//指向自己newnode->next = newnode->prev = newnode;return newnode;
}

尾部插入数据

单链表

//尾插
void SLTPushBack(SLTNode** pphead, SLTDatatype x)
{//传的参数不为空assert(pphead);SLTNode*newnode = SLTbuyNode(x);//链表为空,新节点作为phead//*pphead是指向第一个节点的指针if (*pphead == NULL)//头节点为空{*pphead = newnode;return;}//链表不为空,找尾节点//ptail作为尾节点SLTNode* ptail = *pphead;//先方向,后数据while (ptail->next){ptail = ptail->next;}ptail->next = newnode;
}

双向链表

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = SLTBuyNode(x);newnode->next = phead;newnode->prev = phead->prev;phead->prev->next = newnode;phead->prev = newnode;
}

头部插入数据

单链表 

//头插
void SLTPushFront(SLTNode** pphead, SLTDatatype x)
{//传参有效assert(pphead);//开辟空间,新数据进入SLTNode* newnode = SLTbuyNode(x);//先方向,后数据newnode->next = *pphead;*pphead = newnode;
}

双向链表

//头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = SLTBuyNode(x);newnode->next = phead->next;newnode->prev = phead;phead->next = newnode;phead->prev = newnode->prev->prev;
}

尾部删除数据

单链表

//尾删
void SLTPopBack(SLTNode** pphead)
{//保证传参数据有效assert(pphead);//链表不能为空assert(*pphead);//链表不为空//链表只有一个节点if ((*pphead)->next==NULL){free(*pphead);*pphead = NULL;return;}//有多个节点SLTNode* prev = NULL;SLTNode* ptail = *pphead;while (prev->next){prev = ptail;ptail = ptail->next;}prev = NULL;//销毁尾节点free(ptail);ptail = NULL;
}

双向链表

//尾删
void LTPopBack(LTNode* phead)
{assert(phead);LTNode* del = phead->prev;del->prev->next = phead;phead->prev = del->prev;free(del);del = NULL;
}

头部删除数据

单链表

//头删
void SLTPopFront(SLTNode** pphead)
{//保证传参有效assert(pphead);//保证链表有效assert(*pphead);//让第二个节点成为新的头SLTNode* next = (*pphead)->next;//把旧的头节点释放掉free(*pphead);*pphead = next;//第一个节点 = 原来第二个节点
}

双向链表

//头删
void LTPopFront(LTNode* phead)
{assert(phead);LTNode* del = phead->next;phead->next = del->next;del->next->prev = phead;free(del);del = NULL;
}

查找

单链表 

SLTNode* SLTFind(SLTNode** pphead, SLTDatatype x)
{//保证传参有效assert(pphead);//遍历链表SLTNode* pcur = *pphead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}//没有找到return NULL;
}

双向链表 

//查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){if (pcur->dada == x){return pcur;}pcur = pcur->next;}return NULL;
}

在指定位置之前插入数据 

单链表

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDatatype x)
{//保证传参有效assert(pphead);//保证指定位置数据有效assert(pos);//链表也不能为空assert(*pphead);//新节点,开辟新空间SLTNode* newnode = SLTbuyNode(x);//pos刚好是头节点if (newnode->next = *pphead){//头插SLTPushFront(pphead, x);return;}//pos不是头节点的情况SLTNode* prev = *pphead;if (prev->next != pos){prev = prev->next;}prev->next = newnode;newnode->next = pos;
}

在指定位置之后插入数据

单链表

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDatatype x)
{//保证目标数据有效assert(pos);//创建新节点SLTNode* newnode = SLTbuyNode(x);//先方向,后数据newnode->next = pos->next;pos->next = newnode;
}

双向链表 

//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = SLTBuyNode(x);newnode->prev = pos;newnode->next = pos->next;pos->next = newnode;pos->next->prev = newnode;
}

 删除指定位置数据

单链表

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{//保证传的参数有效assert(pphead);//保证单链表有效assert(*pphead);//保证目标数据有效assert(pos);//pos刚好是头节点,没有前驱节点if (*pphead == pos){//头删SLTPopFront(pphead);return;}//pos不是头节点SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//释放prev->next = pos->next;free(pos);pos = NULL;
}

双向链表

//删除pos位置的数据
void LTErase(LTNode* pos)
{assert(pos);LTNode* del = pos;pos->prev->next = pos->next;pos->next->prev = pos->prev;free(del);del = NULL;
}

删除指定位置后的数据

单链表

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{//保证目标数据有效assert(pos);//pos->next数据有效assert(pos->next);SLTNode* del = pos->next;pos->next = pos->next->next;//释放free(del);del = NULL;
}

销毁链表

单链表

//销毁链表
void SListDesTroy(SLTNode** pphead)
{//保证传的参数有效assert(pphead);//保证链表有效assert(*pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

双向链表

//销毁
void LTDesTroy(LTNode* phead)
{//哨兵位不能为空assert(phead);LTNode* pcur = phead->next;while(pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}free(phead);phead = NULL;
}

***********************************************************分割线*****************************************************************************
完结!!!
感谢浏览和阅读。

等等等等一下,分享最近喜欢的一句话:

“成为正确答案的第一步,相信自己会是正确答案”。

我是白子寰,如果你喜欢我的作品,不妨你留个点赞+关注让我知道你曾来过。
你的点赞和关注是我持续写作的动力!!! 
好了划走吧。

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

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

相关文章

react query 学习笔记

文章目录 react query 学习笔记查询客户端 QueryClient获取查询客户端 useQueryClient异步重新请求数据 queryClient.fetchQuery /使查询失效 queryClient.invalidateQueries 与 重新请求数据queryClient.refetchQueries 查询 QueriesuseQuery查询配置对象查询的键值 Query Key…

力扣 | 24. 两两交换链表中的节点

两两交换链表中的节点 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 输入:head 1->2->3->4->5->NULL 输出:2->1-&g…

互联网轻量级框架整合之MyBatis核心组件

在看本篇内容之前,最好先理解一下Hibernate和MyBatis的本质区别,这篇Hibernate和MyBatis使用对比实例做了实际的代码级对比,而MyBatis作为更适合互联网产品的持久层首选必定有必然的原因 MyBatis核心组件 MyBatis能够成为数据持久层首选框&a…

【博客710】victoriametrics数据写入的pull和push模式以及优缺点

victoriametrics数据写入的pull和push模式以及优缺点 example: curl -d ‘{“metric”:{“name”:“foo”,“job”:“node_exporter”},“values”:[0,1,2],“timestamps”:[1549891472010,1549891487724,1549891503438]}’ -X POST ‘http://localhost:8428/api/v1…

:app debug:armeabi-v7a failed to configure C/C++

报错信息 由于刚换电脑不久,新建native c工程时,出现报错如下: :app debug:armeabi-v7a failed to configure C/C null java.lang.NullPointerExceptionat com.android.build.gradle.tasks.CmakeQueryMetadataGenerator.getProcessBuilder(…

成功转行Python工程师,年薪30W+,经验总结都在这!

都说郎怕入错行,行业对职场人的影响不言而喻。我们身边有很多和自己起点差不多的人,读了差不多的高中,差不多的大学,但是有的人突然一飞冲天,大House、移民、海外置业、全球旅行成了最常见的话题,出入私立医…

多模态 ——LLaVA 集成先进图像理解与自然语言交互GPT-4的大模型

概述 提出了一种大型模型 LLaVA,它使用 GPT-4 生成多模态语言图像指令跟随数据,并利用该数据将视觉和语言理解融为一体。初步实验表明,LLaVA 展示了出色的多模态聊天能力,在合成多模态指令上的表现优于 GPT-4。 在科学质量保证中…

20240327-1-评测指标面试题

评测指标面试题 metric主要用来评测机器学习模型的好坏程度,不同的任务应该选择不同的评价指标,分类,回归和排序问题应该选择不同的评价函数. 不同的问题应该不同对待,即使都是分类问题也不应该唯评价函数论,不同问题不同分析. 回归(Regression) 平均绝对误差(MAE) 平均绝对…

[lesson26]类的静态成员函数

类的静态成员函数 静态成员函数 在C中可以定义静态成员函数 静态成员函数是类中特殊的成员函数静态成员函数属于整个类所有可以通过类名直接访问公有静态成员函数可以通过对象名访问公有静态成员函数 静态成员函数的定义 直接通过static关键字修饰成员函数 静态成员函数 vs…

Gradle 实战 - 命令行传递-ApiHug准备-工具篇-013

🤗 ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱,有温度,有质量,有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace ApiHug …

让人迷糊的ThreadLocalMap,看清他的本质

ThreadLocalMap ThreadLocalMap是ThreadLocal的内部类,主要提供了数据存储和获取的API和存储真实数据的数据结构 我们怎么才能更好的理解这个数据机构呢,首先给出答案:其实我们被他的名字弄迷糊了,他存数据的结构其实本质上是一…

生产事故:线程管理不善诱发P0故障

背景 处于业务诉求,需要建立一个统一的调度平台,最终是基于 Dolphinscheduler 的 V1.3.6 版本去做二次开发。在平台调研建立时,这个版本是最新的版本 命运之轮开始转动 事故 表象 上班后业务部门反馈工作流阻塞,登录系统发现大…