数据结构——链表(双向链表)

大家好,我是小峰,今天给大家讲解的是双向链表,我们先来看看链表的结构。

链表分类

这里带头是哨兵位的头节点

3. 循环与非循环

我们排列一些就可以看出链表的结构种类

这些链表的操作大都差不多

我们今天讲解的是双向带头循环链表

带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都
是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带
来很多优势,实现反而简单了,后面我们代码实现了就知道了。
首先是链表基础结构

创建返回链表的头结点

//创建并返回链表表头listnode* listcj() {listnode* ps = (listnode*)malloc(sizeof(CMMlet) + 2*sizeof(listnode*));ps->next = ps;ps->prev = ps;return ps;
}

这是链表的头节点

那么我们接下来实现一个尾插

尾插数据

void listwc(listnode* pead) {listnode* cur=listcj();listnode* ps = pead->next;//连接ps->next = cur;cur->prev = ps;cur->next = pead;pead->prev = cur;}

我们在写个打印函数

链表打印

//链表打印void listdy(listnode* pead) {listnode* cur = pead->next;printf("哨兵位");while (cur != pead) {printf("<=>%d", cur->SZ);cur = cur->next;}printf("\n");
}

那接下来我们就可以测试一下我们写的尾插数据

老规矩我们分装一个函数来测试

头插数据

//头插数据
void listtc(listnode* pead, CMMlet n) {listnode* ps = listcj();listnode* cur = pead->next;pead->next = ps;ps->prev = pead;cur->prev = ps;ps->next = cur;ps->SZ = n;
}

测试结果

头删数据

//头删数据
void listts(listnode* pead) {listnode* pt = pead->next;listnode* ps = pead->next->next;free(pt);ps->prev = pead;pead->next = ps;
}

这个代码是有点小问题的大家可以想想如果参数只有头节点呢?

最后我们是不是会出现空指针问题?

这时我们就要用到断言了,但我们发现断言的条件也不好写,这时我们的bool类型就要大展身手了

//bool判断
bool listpd(listnode* pead) {if (pead->next == pead && pead->prev == pead) {return false;}else {return true;}
}

修改后的代码如下

//头删数据
void listts(listnode* pead) {assert(pead);assert(listpd(pead));listnode* pt = pead->next;listnode* ps = pead->next->next;free(pt);ps->prev = pead;pead->next = ps;
}

我们测试一下

当我们再删除时

它就会报错,并提示我们在哪一行。

尾删数据

//尾删数据
void listws(listnode* pead) {assert(pead);assert(listpd(pead));listnode* ps = pead->prev;listnode* pt = ps->prev;free(ps);pt->next = pead;pead->prev = pt;
}

查找数据

与单链表类似我们来试试

//查找数据listnode* listcz(listnode* pead, CMMlet n) {assert(pead);listnode* ps = pead->next;while (ps != pead) {if (ps->SZ == n) {return ps;}else {ps = ps->next;}}return NULL;
}

我们测试一下

在pos的前面插入数据

 //在pos前面插入数据void listposcr(listnode* pos, CMMlet n) {listnode* ps = pos->prev;listnode*pt=listcj();pt->next = pos;pos->prev = pt;pt->prev = ps;ps->next = pt;pt->SZ = n;}

测试一下

删除pos位置的数据

//删除pos位置的数据void listpossc(listnode* pos) {assert(pos);assert(listpd(pos));listnode* prev = pos->prev;listnode* next = pos->next;free(pos);prev->next = next;next->prev = prev;}

测试一下

销毁链表

//销毁链表void listxh(listnode* pead) {listnode* cur = pead->next;listnode* ps = cur->next;while (cur != pead) {free(cur);cur = ps;ps = ps->next;}pead->next = pead;pead->prev = pead;}

测试一下

这就是双向带头循环链表的所有操作了

下面就是本节的所有代码了

# include<stdio.h>
# include<stdlib.h>
# include<stdbool.h>
# include<assert.h>typedef int CMMlet;
typedef struct listnode  listnode;struct listnode {CMMlet SZ;//上一个节点listnode* prev;//下一个节点listnode* next;
};//创建并返回链表表头listnode* listcj() {listnode* ps = (listnode*)malloc(sizeof(CMMlet) + 2*sizeof(listnode*));ps->next = ps;ps->prev = ps;return ps;
}//尾插数据void listwc(listnode* pead,CMMlet n) {listnode* cur=listcj();listnode* ps = pead->prev;//连接ps->next = cur;cur->prev = ps;cur->next = pead;pead->prev = cur;cur->SZ = n;}//链表打印void listdy(listnode* pead) {listnode* cur = pead->next;printf("哨兵位");while (cur != pead) {printf("<=>%d", cur->SZ);cur = cur->next;}printf("\n");
}//头插数据
void listtc(listnode* pead, CMMlet n) {listnode* ps = listcj();listnode* cur = pead->next;pead->next = ps;ps->prev = pead;cur->prev = ps;ps->next = cur;ps->SZ = n;
}//bool判断
bool listpd(listnode* pead) {if (pead->next == pead && pead->prev == pead) {return false;}else {return true;}
}//头删数据
void listts(listnode* pead) {assert(pead);assert(listpd(pead));listnode* pt = pead->next;listnode* ps = pead->next->next;free(pt);ps->prev = pead;pead->next = ps;
}//尾删数据
void listws(listnode* pead) {assert(pead);assert(listpd(pead));listnode* ps = pead->prev;listnode* pt = ps->prev;free(ps);pt->next = pead;pead->prev = pt;
}
//查找数据listnode* listcz(listnode* pead, CMMlet n) {assert(pead);listnode* ps = pead->next;while (ps != pead) {if (ps->SZ == n) {return ps;}else {ps = ps->next;}}return NULL;
}//在pos前面插入数据void listposcr(listnode* pos, CMMlet n) {listnode* ps = pos->prev;listnode*pt=listcj();pt->next = pos;pos->prev = pt;pt->prev = ps;ps->next = pt;pt->SZ = n;}//删除pos位置的数据void listpossc(listnode* pos) {assert(pos);assert(listpd(pos));listnode* prev = pos->prev;listnode* next = pos->next;free(pos);prev->next = next;next->prev = prev;}//销毁链表void listxh(listnode* pead) {listnode* cur = pead->next;listnode* ps = cur->next;while (cur != pead) {free(cur);cur = ps;ps = ps->next;}pead->next = pead;pead->prev = pead;}void listcheshi() {listnode* pead = listcj();listtc(pead, 1);listtc(pead, 2);listtc(pead, 3);listtc(pead, 4);listtc(pead, 5);listdy(pead);listxh(pead);listdy(pead);}int main() {//测试函数listcheshi();return 0;
}

  以上就是全部内容了,如果有错误或者不足的地方欢迎大家给予建议。 

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

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

相关文章

BGP实训

BGP基础配置实训 实验拓扑 注&#xff1a;如无特别说明&#xff0c;描述中的 R1 或 SW1 对应拓扑中设备名称末尾数字为 1 的设备&#xff0c;R2 或 SW2 对应拓扑中设备名称末尾数字为2的设备&#xff0c;以此类推&#xff1b;另外&#xff0c;同一网段中&#xff0c;IP 地址的主…

【数据挖掘】实验5:数据预处理(2)

验5&#xff1a;数据预处理&#xff08;2&#xff09; 一&#xff1a;实验目的与要求 1&#xff1a;熟悉和掌握数据预处理&#xff0c;学习数据清洗、数据集成、数据变换、数据规约、R语言中主要数据预处理函数。 二&#xff1a;实验知识点总结 1&#xff1a;数据集成是将多个…

boost::asio::ip::tcp/udp::socket::release 函数为什么限制 Windows 8.1 才可以调用?

如本文题目所示&#xff0c;这是因为只有在 Windows 8.1&#xff08;Windows Server 2012 RC&#xff09;及以上 Windows 操作版本才提供了运行时&#xff0c;修改/删除完成端口关联的ABI接口。 boost::asio 在 release 函数底层实现之中是调用了 FileReplaceCompletionInform…

git仓库太大只下载单个文件或文件夹

有没有这样的苦恼&#xff1a;仓库太大&#xff0c;只想下载其中某些文件(夹)&#xff1f; 一招解决&#xff1a;bash down_folder_from_git.sh 运行前&#xff0c;先修改开头三个变量 原理: 稀疏检出 让工作树仅包含自定义的文件 #!/usr/bin/bash addrhttps://github.com/fac…

【edge浏览器无法登录某些网站,以及迅雷插件无法生效的解决办法】

edge浏览器无法登录某些网站&#xff0c;以及迅雷插件无法生效的解决办法 edge浏览器无法登录某些网站&#xff0c;但chrome浏览器可以登录浏览器插件无法使用&#xff0c;比如迅雷如果重装插件重装浏览器重装迅雷后仍然出现问题 edge浏览器无法登录某些网站&#xff0c;但chro…

niushop单商户V5多店版源码分享三端uniapp打包方法包括PC端_小程序或h5端打包_收银端打包_APP端打包_商户端

目前多店版有四端uniapp&#xff0c;包括PC端uniapp&#xff0c;商家端uniapp&#xff0c;收银端uniapp&#xff0c;门店手机端uniapp&#xff0c;下面我总结下这些端的打包流程希望能帮助到大家&#xff0c;需要交流的可以看我昵称或者点我头像关注我分享代码和教程 一.niush…

IoT网关在智能制造工厂生产线监控与管理中的应用-天拓四方

随着工业4.0时代的到来&#xff0c;智能制造已成为工业发展的重要方向。IoT网关在智能制造工厂中扮演着关键角色&#xff0c;它能够实现设备间的互联互通、数据的实时采集与处理&#xff0c;以及生产线的智能监控与管理。本案例将详细介绍IoT网关在智能制造工厂生产线监控与管理…

constexpr与std::is_same_v碰撞会产生什么火花?

1. 只编译会用到的if分支 示例代码一中&#xff0c;checkType_v1和checkType_v2两个函数的区别就是if的条件里一个加了constexpr一个没加&#xff0c;加与不加从结果来看都一样&#xff0c;那在编译时和运行时各有什么区别呢&#xff1f; 示例代码一&#xff0c;test_01.cpp&…

与鲸同行,智领未来!和鲸科技“人工智能+X”学科建设合作交流会(北京站)圆满结束!

在国家加快发展新质生产力的大背景下&#xff0c;3月25日下午&#xff0c;和鲸科技 2024 年“人工智能X”学科建设合作交流会&#xff08;北京站&#xff09;暨“AIX”实验室建设与供应商选型座谈会顺利召开。为提供更为集中和专业的讨论环境&#xff0c;本次会议特别采取闭门审…

海豚【货运系统源码】货运小程序【用户端+司机端app】源码物流系统搬家系统源码师傅接单

技术栈&#xff1a;前端uniapp后端vuethinkphp 主要功能&#xff1a; 不通车型配置不通价格参数 多城市定位服务 支持发货地 途径地 目的地智能费用计算 支持日期时间 预约下单 支持添加跟单人数选择 支持下单优惠券抵扣 支持司机收藏订单评价 支持订单状态消息通知 支…

抢先一步,搞定阿里面试难题——双亲委派机制揭秘!

希望本文对你有所帮助,欢迎继续关注我的公众号“知其然亦知其所以然”,一起探索更多有趣的技术话题! 大家好,我是小米,欢迎来到我的微信公众号!今天,我们将深入探讨一道备受关注的面试题目——“双亲委派机制”。这个话题是阿里巴巴等顶尖科技公司面试中常常涉及的一环…

企业数据资产管理的战略价值与实施策略

一、引言 数据资产不仅记录了企业的历史运营情况&#xff0c;更能够揭示市场的未来趋势&#xff0c;为企业的决策提供有力支持。因此&#xff0c;如何有效地管理和利用数据资产&#xff0c;已经成为企业竞争力的重要体现。本文将探讨企业数据资产管理的战略价值与实施策略&…