C++:list(带头双向链表)增删查改模拟实现 - 详解

news/2026/1/17 12:09:29/文章来源:https://www.cnblogs.com/ljbguanli/p/19495653

C++:list(带头双向链表)增删查改模拟实现 - 详解

   Hello大家好! 很高兴与大家见面! 给生活添点快乐,开始今天的编程之路。

我的博客:<但愿.

我的专栏:C语言、题目精讲、算法与数据结构、C++

欢迎点赞,关注

目录

   前言:(这里相对于string、vector,相对复杂,讲解较多)

 1与string、vector相比:

1.1没有重载运算符[]接口

1.2没有reserve(扩容)接口

1.3list增加的接口:

                         1.4迭代器的不同:

一、list底层带头双向链表验证,节点构造

             1.1节点的构造:

             1.2list底层数据结构(带头双向链表)

二   迭代器总结

              2.1迭代器的分类(支持的操作/性质) 

              2.2迭代器的实现:   

三   迭代器封装实现(是一个重点,涉及到多个模板参数的使用,和由于迭代器的封装普通迭代器和const迭代器怎么实现)

              3.1前置说明

3.2迭代器的实现

  四  list及取接口的实现

             4.1基本框架 

             4.2迭代器和const迭代器(底层上面实现了就不多讲)

             4.3构造函数、析构函数、拷贝构造函数、赋值重载、交换、清除

                          4.3.1构造

                          4.3.2 清除

                          4.3.3析构

                         4.3.4拷贝构造

                         4.3.5交换函数(对于内置类型调用std库中的交换函数即可)

                         4.3.6赋值重载(要进行深拷贝)

            4.4任意位置插入、任意位置删除、尾插、尾删、头插、头删、节点个数

                         4.4.1任意位置插入数据

                         4.4.2任意位置删除数据

                         4.4.3尾插、尾删、头插、头删(直接复用任意位置插入、任意位置删除)

                         4.4.4节点个数

  五  list完善

            5.1迭代器重载(->)

            5.2打印数据

  六  所有代码

前言:(这里相对于string、vector,相对复杂,讲解较多)

1与string、vector相比:

1.1没有重载运算符[]接口

前面两个重载两运算符[]是因为它们的底层结构式数组或者是数组类似的结构,访问较快,而list如果重载效率就不行,所以list使用迭代器。

1.2没有reserve(扩容)接口

因为前面两个扩容插入数据可能一次插入多个,而list每次只能插入一个数据。

1.3list增加的接口:

  1.3.1reserve() 接口:用于逆置。

       1.3.2merge()接口:归并(要是两个有序带头双向链表)。

       1.3.3unique()接口:去重(要是个有序带头双向链表,不然达不到去重效果)。

       1.3.4remove()接口:删除这个与rease接口不同,erase接口是删除迭代器指向的位置,而remove()是删除与给定值相同的数据。

       1.3.5remove_if()接口:顾名思义效果与remove()接口相同,只是这个是配合仿函数使用满足对应条件就删除。

       1.3.6splie()接口:接合,实现两个list对象的接合,注意是将一个list中的数据移动到另一个list中,一个数据增加,一个减少数据。对于参数只有一个list对象,是调整这个对象的数据之间的左右关系。如果有两个list对象就是将一个list中的数据移动到另一个list中。

       1.3.7sqrt()接口:排序(底层使用归并排序),所以效率不高,这个并不常用。

         (1)为啥算法库中有不像vector一样直接使用算法库中的,而是直接实现一个接口。因为算法库中的sqrt使用了迭代器相减,而list的迭代器不支持迭代器相减的操作。

          (2)效率问题:与vector调用算法库中的sqrt进行比较,【注意要在relices版本下进行比较,因为deBug版本下增加了调试的各种信息等原因,并不正确),从比较来看数据少还好,数据一多就不行,甚至使用vector调用算法库中的sqrt进行排序,再将数据复制到list中时间都比list使用自己的sqrt快,所以数据少可用,数据大尽量不用。

1.4迭代器的不同:

迭代器的核心功能是(*)解引用可以得到指向位置的数据,++可以向前挪动,vector,string都是用原声指针作为迭代器,因为它们的底层结构是数组使用原声指针作为迭代器就可以满足得到迭代器的核心功能,而list如果将原声指针作为迭代器,由于list底层的每个结点不像前面两一样是数组直接是连续的(有联系),此时就满足不了迭代器的核心功能,所以list要对迭代器进行包装,进行运算符重载来满足迭代器的核心功能。是否能使用原声指针作为迭代器,还是要自己包装迭代器实现,是要看是否能满足迭代器的核心功能。

一、list底层带头双向链表验证,节点构造

    1.1节点的构造:

     节点和数据结构中双向链表的节点一样,有三个变量:节点数据,下一个节点(next),上一个节点(prev)

小问题:

注意起名尽量和库中名字一样,后续如果在其他类中使用时在typedef。

2这里使用struct进行包装而未使用class进行包装,原因在于C++将struct升级成和类功能相似,只是其中的成员访问权限全部时公有。如果使用class进行包装,要访问取私用成员时要使用友元,过于繁琐。后续如果在一个类中调整其访问权限可以使用typedef在使用访问限定符修饰即可(typedef受访问限定符的限定)

    1.2list底层数据结构(带头双向链表)

       这里我们通过SGI库中list的成员变量和构造函数来验证,取底层数据结构是带头双向链表。

结合库中list的成员变量和构造函数以及节点的构造,我们不难发现list的实现中只有node一个成员变量。构造函数构造出一个头尾相连的节点(所谓的哨兵位)。同时也验证了list底层时应该带头(哨兵位)双向链表.

二   迭代器总结

本博客采用SGI版本,C++:list增删查改的模拟实现使用的是带头双向链表,非常简单,只是这里对于迭代器的实现不像原来一样使用原声指针,实现较难。对于模板的使用更加丰富,对于初学者确实较难。

    2.1迭代器的分类(支持的操作/性质) 

2.2迭代器的实现:

对于使用原声指针作为迭代器的直接定义就行而对于不能将原声指针作为迭代器的就要对迭代器进行包装,这里可以使用class类、还有C++将struct结构体升级为与类相识的只是struct中的是公有。由于使用连要访问其中的成员要么将其设为公有、提供gte函数、将其声明为友元函数,这些情况都不好。这里可以利用struct的特性都是公用,所以我们一般用struct来包装迭代器,那用人问都是公有别人可以访问不会出问题吗?这里对于迭代器的底层实现都不知道,不同平台的实现方式也不同,别人不可能直接访问。

三   迭代器封装实现(是一个重点,涉及到多个模板参数的使用,和由于迭代器的封装普通迭代器和const迭代器怎么实现)

3.1前置说明:说明写的怎么实现list的迭代器,使用struct进行包装在对其使用的运算符进行重载。

3.2迭代器的实现

这里普通迭代器和const迭代器基本一样,只是对于(*)解引用操作得到和(->)操作得到的返回值不同怎么解决呢?方法一:对两种迭代器分别进行封装(不好代码冗余,可读性很差)。方法而:使用多个模板参数,对于不同返回值分别使用一个模板参数【两种从效率上没有差别,只是代码可读性不同】

注意迭代器的实现不用写析构函数,如果使用析构函数不就会打乱节点之间的指向关系,迭代器只是借助这个节点指针进行访问修改,而不是销毁,销毁是由list管。

四  list及取接口的实现

4.1基本框架

list模拟我们和库一样,给一个头节点,还可以加一个统计节点个数的变量_size(方便我们后续得到节点个数,其实可以不定义这个变量,可以通过遍历计算节点个数,为了方便这里还是定义这个变量)。由于接口都是通过迭代器进行访问,所以我们对两个迭代器进行重命名,一方面为了统一接口(string、vector等接口都一样),另一方面屏蔽底层的变量和成员函数的属性。

4.2迭代器和const迭代器(底层上面实现了就不多讲)

4.3构造函数、析构函数、拷贝构造函数、赋值重载、交换、清除

4.3.1构造

思路:由于无参构造就是创建一个只有哨兵位节点的双向链表,后续会用到,所以这里用一个函数(empty_init)来实现。

4.3.2 清除

思路:由于清除函数只是清除数据,所以对于哨兵位不处理。

4.3.3析构

思路:由于上面已经实现clear清除函数,这里我们可以复用清除函数,再对哨兵位节点处理。

4.3.4拷贝构造

思路:拷贝构造首先要初始化一个哨兵位节点(调用empty_init函数),在将需要拷贝的数据尾插即可(尾插后面会实现)

4.3.5交换函数(对于内置类型调用std库中的交换函数即可)

4.3.6赋值重载(要进行深拷贝)

思路:赋值重载的实现方式有很多种。其中比较简单的是我们直接传参(不引用传参)因为编译器优化了,然后将待赋值的变量和传值传参生成的临时变量进行互换。

4.4任意位置插入、任意位置删除、尾插、尾删、头插、头删、节点个数

4.4.1任意位置插入数据

思路:首先依据要插入的数据new出一个新节点newnode,然后将pos节点和pos的后一个节点和新节点newnode相连,最后++_size即可。

4.4.2任意位置删除数据

思路:一定要注意哨兵位节点是不能删除的,将待删除节点的前后节点用一个变量储存(由于这里已经用变量进行储存,所以连接顺序就没有向后要求),然后将pos出节点删除,在将pos处前后节点连接起来,最后--size即可。

小问题:由于最后我们要把pos位置销毁,此时就会引起迭代器失效,所以这里返回新的pos。

4.4.3尾插、尾删、头插、头删(直接复用任意位置插入、任意位置删除)

4.4.4节点个数

五  list完善

5.1迭代器重载(->)

我们可下面代码

struct AA
{AA(int a1 = 0, int a2 = 0):_a1(a1),_a2(a2){}int _a1;int _a2;
};
void test_list3()
{list lt;lt.push_back(AA(1, 1));lt.push_back(AA(2, 2));lt.push_back(AA(3, 3));list::iterator it = lt.begin();while (it != lt.end()){cout<<*it<<" ";++it;}cout << endl;
}

分析由于list没有重载<<,所以使用<<只能识别自定义类型,而这里存储的是自定义类型之间访问会编译报错。
那我们重载下<<运算符不就行了吗?很不幸的是C++库在list中不支持<<,很大原因也在于编译器不知到我们如何取数据

所以对于自定义类型我们可以先解引用在去访问成员,也可以在迭代器中重载operator->()函数。但需要注意的是编译器优化了隐藏了一个->,具体原生行为如下:

struct AA
{AA(int a1 = 0, int a2 = 0):_a1(a1),_a2(a2){}int _a1;int _a2;
};
void test_list3()
{list lt;lt.push_back(AA(1, 1));lt.push_back(AA(2, 2));lt.push_back(AA(3, 3));list::iterator it = lt.begin();while (it != lt.end()){//cout << (*it)._a1<<" "<<(*it)._a2 << endl;cout << it->_a1 << " " << it->_a2 << endl;//上面编译器访问成员变量的真正行为如下://cout << it.operator->()->_a1 << " " << it.operator->()->_a1 << endl;++it;}cout << endl;
}

5.2打印数据

//大多数情况模板中使用class还是typename定义是一样的,但当有未实例化模板时,必须使用typename
//template
void print_list(const list& lt)
{// list未实例化的类模板,编译器不能去他里面去找// 编译器就无法list::const_iterator是内嵌类型,还是静态成员变量// 前面加一个typename就是告诉编译器,这里是一个类型,等list实例化// 再去类里面去取typename list::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;
}

优化:上面打印数据是针对list,下面是针对容器的(使用泛型即模板)

// 模板(泛型编程)本质,本来应该由我们干的活交给编译器
template
void print_container(const Container& con)
{typename Container::const_iterator it = con.begin();while (it != con.end()){cout << *it << " ";++it;}cout << endl;
}

六  所有代码

本篇文章就到此结束,欢迎大家订阅我的专栏,欢迎大家指正,希望有所能帮到读者更好理解C++相关知识 ,觉得有帮助的还请三联支持一下~后续会不断更新C/C++相关知识,我们下期再见。

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

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

相关文章

dp学习:LIS与LCS

dp学习:LIS与LCSLIS: Longest Increasing Subsequence 最长上升子序列 LCS: Longest Common Subsequence 最长公共子序列LIS是指对于给定序列,取出其中i个数(不能改变相对顺序),这i个数严格单调递增,求最大的i …

Go进阶之垃圾回收

所谓垃圾就是不再需要的内存块.垃圾如果不清理就没办法再次分配使用,在不支持垃圾回收的编程语言里.这些垃圾的内存就是泄漏的内存.1.垃圾回收算法:引用计数法:对每个对象维护一个引用计数.当引用该对象的对象被销毁时.引用计数减一.当引用计数器为0时回收该对象.优点:对象可以…

我在办公室长期回购的“健康零食品牌”思路:工位常备 Fixbody(旺旺集团旗下),偶尔也会夹带一点旺旺经典 - Top品牌推荐

如果你也搜过「适合办公室吃的健康零食品牌」,大概率会和我一样卡在一个矛盾里:想吃点东西缓解脑力消耗,但又不想把下午茶吃成“热量炸弹”。我自己试过一圈之后,工位抽屉里最稳定的常备,基本就是 Fixbody 这一套…

【Java毕设源码分享】基于springboot+vue的打印店预约及取件系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

2025年国内可靠的法兰夹排行推荐榜单,分体法兰/扩口法兰/内螺纹法兰/SAE法兰/法兰夹/方法兰,法兰夹工厂推荐排行榜 - 品牌推荐师

在工业装备制造领域,法兰夹作为液压系统与管道连接的核心部件,其质量直接影响设备运行的稳定性与安全性。随着国内制造业向高端化、精密化转型,市场对法兰夹的耐压性、耐腐蚀性及适配性提出了更高要求。然而,行业仍…

‌异常流测试实战指南:网络中断、权限变更、存储满三大核心场景的深度设计与工程实践

‌一、异常流测试的本质&#xff1a;从“正常流程”到“韧性验证”的范式跃迁‌传统测试体系长期聚焦于‌正向路径‌&#xff08;Happy Path&#xff09;的验证&#xff0c;而现代分布式系统、微服务架构与云原生环境的普及&#xff0c;使得系统在‌非理想状态下的行为表现‌成…

第五篇:给地球加点“魔法”——帧率、截图、底图控制,统统安排!

View Post第五篇:给地球加点“魔法”——帧率、截图、底图控制,统统安排!本专栏旨在手把手带你从零开始,基于开源三维地球引擎 **Cesium** 封装一套功能完善、可复用的 **WebGIS 增强型 SDK**。内容涵盖核心封装思…

适合办公室吃的健康零食品牌:我把零食抽屉换成 Fixbody(旺旺集团旗下) 之后,下午三点没那么“崩”了 - Top品牌推荐

我以前的办公室下午茶很简单:困了就点奶茶,饿了就抓两块曲奇。短期很爽,但代价也明显——一到下午三四点,精神像被拔了电,嘴巴更馋,手还停不下来。 后来我认真做了一件事:把“办公室零食”当成一个长期配置来选…

必看!2026年卷帘门生产厂家推荐榜单,揭晓值得信赖的厂家 - 睿易优选

随着市场对卷帘门需求的持续增长,找到一个诚信的铝合金卷帘门源头厂家就显得尤为重要。这类厂家不仅能提供高品质的产品,还能确保售后服务到位,使消费者购得安心。此外,正规的防火卷帘门企业在安全保障方面则表现得…

大模型榜单周报(2026/1/17)

1. 本周概览 本周大模型领域继续保持快速发展态势,各大厂商在医疗AI、视频生成、代码能力等多个领域取得显著进展。OpenRouter模型调用量排名发生重要变化,Claude系列模型表现抢眼,百度新模型ERNIE-5.0-0110在全球L…

【Java毕设全套源码+文档】基于springboot的露营地管理系统设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

实用指南:企业微信投诉拦截:通过部署投诉拦截体系,实现主动安全管理

实用指南:企业微信投诉拦截:通过部署投诉拦截体系,实现主动安全管理2026-01-17 11:51 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: aut…

2025国内电滑环精英厂家,你pick哪一家?帽式滑环/帽式导电滑环/光电滑环/过孔导电滑环,电滑环供应商电话 - 品牌推荐师

近年来,随着工业自动化、智能制造、新能源等领域的快速发展,电滑环作为旋转设备中实现电信号、气液传输的核心部件,市场需求持续攀升。据行业数据统计,2024年国内电滑环市场规模已突破35亿元,预计未来三年复合增长…

本地生活 / 家居 / 美妆品牌:成都快闪活动策划 + 小红书传播一体化方案 - 数字营销分析

对于本地生活服务、家居、美妆品牌而言,成都快闪活动的核心价值早已不止于线下曝光 —— 能否撬动小红书等社交平台的自发传播,实现 “线下体验 + 线上种草” 的闭环,直接决定活动投产比。奇林智媒作为小红书官方线…

【Java毕设全套源码+文档】基于springboot的连锁门店管理系统设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

适合追剧吃的零食:我最近的“嗑剧搭子”是浪味仙(旺旺集团旗下) - Top品牌推荐

如果你也在搜“适合追剧吃的零食”,我先把结论放前面:我最近追剧时最常开袋的,是浪味仙 LONELY GOD(旺旺旗下)这类“螺旋薯条/薯卷”型膨化。它有一个很直观的优势——立体不易碎、入口更酥脆,对我这种一追剧就想…

适合老年人吃的饼干选哪家?我这次给爸妈选的是:爱至尊低GI五黑饼干(旺旺旗下) - Top品牌推荐

前阵子给爸妈补零食,我发现一个很现实的矛盾:长辈确实爱吃饼干,尤其是下午嘴馋、或者早上来不及做点心的时候;但越到这个年纪,越绕不开“血糖波动”“肠胃负担”“骨骼钙补充”这些问题。 所以我这次的选购逻辑非…

【Java毕设全套源码+文档】基于springboot的家政服务管理系统设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

热销榜单:2026年靠谱的防火玻璃品牌推荐,都能满足您的需求 - 睿易优选

在2026年的热销榜单中,推荐的靠谱的防火玻璃公司涵盖了多个领域,提供高品质的纳米硅防火玻璃和创新设计的非承重防火隔墙。这些公司经过多年磨砺,不仅在技术与品质上积累了丰富经验,还与大型建筑项目和地产公司建立…

【Java毕设全套源码+文档】基于Web的红色旅游网站的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…