C++语言·list链表(下)

        还是之前说的,因为要写模板,为了避免链接出现问题,我们将所有内容都写到一个文件中去。首先就是画出链表的框架

                

        链表本身只需要一个头节点就足以找到整条链表,而需要它拼接的节点我们再写一个模板。而我们知道list是一个带头双向循环链表,所以再写节点模板是时候将要表现出来双向,在写链表模板的时候要表现出带头和循环。

        之所以要把ListNode设定成struct而不是class,因为再list中的成员函数中要反复访问节点中的成员变量,所以ListNode中的成员变量和成员函数都要设置成public公有的,所以干脆就直接写成struct了。

        本节的重点也是难点就是链表的迭代器

1. 迭代器

        构造析构还有那些接口我们已经熟的不能再熟了,之后再说,这里我们直接进入重点。

        之前 string 和 vector 的迭代器我们都是直接 typdef 出来的,那list的迭代器可不可以也这样做。

                        

        答案当然是不行,前两者都是因为它们的存储空间是在物理上连续的,所以在 ++iterator的时候可以直接访问到下一块内存,显然链表是不行的,因此我们要给链表的迭代器特别写一个类出来,为了重载iterator的 ++iterator *iterator等行为

        这里不建议把这个迭代器写成list的内部类,因为写成内部类之后迭代器不是list的友元啊,之后操作迭代器就会变得异常麻烦。

        ​​​​​​​        ​​​​​​​

        链表的迭代器我们选择用节点的指针。现在我们将迭代器的结构描绘出来,然后记得在list类中typedef一下,达到容器中迭代器的名称一致。

        下面我们实现迭代器类,主要就是重载迭代器的几种操作方式

        ​​​​​​​        ​​​​​​​

        我们的迭代器是不去支持 + 或 - 的因为这个效率很低,就是在O(N)时间复杂度的遍历链表,拷贝构造,析构和赋值也都不需要写,让编译器自动生成浅拷贝就行,因为迭代器的目的是去访问节点,而不是去修改,也不要释放。当然,解引用访问到某个节点之后进行的修改不是说迭代器在修改节点数据,而是利用迭代器访问到了节点之后,在节点中修改它的数据。

        其实迭代器这个东西就是一种封装,Node*指针无法直接完成下一块空间的访问,因此我们就将Node*封装到迭代器中,并且在迭代器中重载实现访问下一块空间的方法。

1.1 begin() end()

                

        end()取出的迭代器就是那个头节点或者说哨兵位,因为迭代器都是左闭右开的嘛

1.2 const_iterator

        因为迭代器跟指针的效果是类似的,const迭代器起到一个迭代器本身可以修改但是其指向内容不能修改的效果,所以const迭代器我们不能在iterator前面简单加一个const,而是要再写一个专门的ListConstIterator类。

        这个类其实和普通的内容都基本一样,我们只需要在*运算符重载的函数前面加const限制返回值就好了。

        ​​​​​​​        ​​​​​​​        

        不过我更推荐的是将const和非const的迭代器类用模板写在一起

        

        在list类中实例迭代器的时候将它们区分开

        ​​​​​​​

        那个Ptr模板是重载->操作符用的,具体内容可以到最后完整代码中查看

2. 构造 析构 赋值操作符重载

2.1 默认构造

        ​​​​​​​        

        默认构造就是建立出那个头节点,或者说哨兵位。

2.2 析构

                 

        我们先写一个清空容器的函数clear,析构就是把容器清空之后再把头节点哨兵位释放掉。

2.3 拷贝构造

        ​​​​​​​        ​​​​​​​        

2.4 赋值操作符重载

                

2.5 initializer_list构造

                

3. 插入与删除

3.1 随机位置插入

        ​​​​​​​        

        双向链表的插入逻辑我就不讲了,详见数据结构章节的链表讲解

数据结构·双向链表-CSDN博客文章浏览阅读1k次,点赞18次,收藏16次。本节讲解了双向链表的结构,以及实现了一个双向链表及功能,不得不说双向链表比单链表写起来简单多了,没有那么多繁琐的条件判断https://blog.csdn.net/atlanteep/article/details/135880386        这里要说的问题就是链表插入时的迭代器会不会失效,事实上是不会的,因为链表不涉及扩容和数据位置的挪动,所以在插入数据的时候迭代器是不会失效的。

        但是在STL标准中,为了各个容器的一致,链表insert也会返回第一个新插入元素的迭代器

3.2 随机位置的删除

        ​​​​​​​        

        随机位置的删除我们要先断言一下,不能说把哨兵位都给删了。

        删除节点是会造成迭代器失效的,STL标准中要返回被删除的最后一个元素之后那个元素的迭代器。

        

3.3 头插头删、尾插尾删

                

        这个纯白给的,只不过注意一下尾删时,要删除哨兵位的前一个节点,而不是删end()位置的节点。

4. 完整代码

#include<assert.h>namespace atl
{template<class T>struct ListNode{ListNode<T>* _next;ListNode<T>* _prev;T _data;ListNode(const T& data = T()):_next(nullptr), _prev(nullptr), _data(data){}};template<class T,class Ref,class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator() = default;ListIterator(Node* node):_node(node){}//++iteratorSelf& operator++(){_node = _node->_next;return *this;}//iterator++Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}//--iteratorSelf& operator--(){_node = _node->_prev;return *this;}//iterator--Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}//*iteratorRef operator*(){return _node->_data;}//iterator->Ptr operator->(){return &_node->_data;}//iterator!=iteratorbool operator!=(const Self& it){return _node != it._node;}//iterator==iteratorbool operator==(const Self& it){return _node == it._node;}};template<class T>class list{typedef ListNode<T> Node;public://迭代器typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;iterator begin(){return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator end()const{return const_iterator(_head);}//默认构造list(){_head = new Node();_head->_next = _head;_head->_prev = _head;}//析构void clear(){auto it = begin();while (it != end()){it = erase(it);}}~list(){clear();delete _head;_head = nullptr;}//拷贝构造list(const list<T>& lt){//创建头节点_head = new Node();_head->_next = _head;_head->_prev = _head;for (const auto& e : lt){push_back(e);}}//赋值操作符重载list<T>& operator=(list<T> lt){std::swap(_head, lt._head);return *this;}//initializer_list构造list(initializer_list<T> il){//创建头节点_head = new Node();_head->_next = _head;_head->_prev = _head;for (const auto& e : il){push_back(e);}}//没有迭代器失效//随机位置插入iterator insert(iterator pos,const T& x){Node* cur = pos._node;Node* newnode = new Node(x);newnode->_prev = cur->_prev;newnode->_next = cur;cur->_prev->_next = newnode;cur->_prev = newnode;return iterator(newnode);}//有迭代器失效//随机位置删除iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;//记录将要返回的迭代器iterator it((cur->_next));cur->_next->_prev = cur->_prev;cur->_prev->_next = cur->_next;delete cur;return it;}//尾插void push_back(const T& x){insert(end(), x);}//尾删void pop_back(){erase(--end());}//头插void push_front(const T& x){insert(begin(), x);}//头删void pop_front(){erase(begin());}private:Node* _head;};
}

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

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

相关文章

Verilog HDL基础知识(一)

引言&#xff1a;本文我们介绍Verilog HDL的基础知识&#xff0c;重点对Verilog HDL的基本语法及其应用要点进行介绍。 1. Verilog HDL概述 什么是Verilog&#xff1f;Verilog是IEEE标准的硬件描述语言&#xff0c;一种基于文本的语言&#xff0c;用于描述最终将在硬件中实现…

数据库设计实例---学习数据库最重要的应用之一

一、引言【可忽略】 在学习“数据库系统概述”这门课程时&#xff0c;我一直很好奇&#xff0c;这样一门必修课&#xff0c;究竟教会了我什么呢&#xff1f; 由于下课后&#xff0c;&#xff0c;没有拓展自己的眼界&#xff0c;上课时又局限于课堂上老师的讲课水平&#xff0c;…

探索数组处理:奇数的筛选与替换

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、数组中的奇数筛选 二、将奇数替换为负一 总结 一、数组中的奇数筛选 在处理数组数据时…

【Qt】初识

一、使用Label显示Hello World 1.ui设计 可以在Qt Designer中拖拽方式进行创建 2.代码方式 在myqwidget.cpp文件中添加下列代码 二、对象树 我们在堆上创建了QLabel类的对象。但是我们没有去delete&#xff0c;这样会产生内存泄漏吗&#xff1f; 答案是不会。label对象会在…

ChatGPT的基本原理是什么?又该如何提高其准确性?

在深入探索如何提升ChatGPT的准确性之前&#xff0c;让我们先来了解一下它的工作原理吧。ChatGPT是一种基于深度学习的自然语言生成模型&#xff0c;它通过预训练和微调两个关键步骤来学习和理解自然语言。 在预训练阶段&#xff0c;ChatGPT会接触到大规模的文本数据集&#x…

输入输出(1)——C++的输入输出概述

目录 一、C的输入输出 (一) C的输入输出 (二&#xff09;C语言的scanf和printf 二、C的输入输出流 (一) iostream类库中有关的类 (二&#xff09; iostream.h头文件的流对象和重载运算符 一、C的输入输出 (一) C的输入输出 之前用到的输入输出&#xff0c;都是以终端…

在做题中学习(62):矩阵区域和

1314. 矩阵区域和 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;二维前缀和 思路&#xff1a;读题画图才能理解意思&#xff1a;dun点点的是mat中的一个数&#xff0c;而要求的answer同位置的数 以点为中心上下左右延长 k 个单位所围成长方形的和。 因为最后answ…

IPV4地址介绍

4.1IP地址简介 目前的全球因特网所采用的协议族是TCP/IP协议族。IP是TCP/IP协议族中网络层的协议&#xff0c;是TCP/IP协议族的核心协议。IP协议定义了一种地址编码&#xff0c;称为IP地址&#xff0c;它是网络中网络段、网络设备接口、主机的编码&#xff0c;它并不是一种物理…

Linux离线一键安装Docker及docker-compose环境

背景&#xff1a; 在当前软件部署运维环境中由于Docker容器化优势越来越明显&#xff0c;因些被许多公司运维所采用&#xff0c;那首先如何快速安装Docker及docker-compose基础环境就第一时间被人们关注&#xff0c;本人同样在经过多次手工逐条用命令安装的过程&#xff0c;整理…

基于51单片机的温湿度控制系统

一.硬件方案 本设计采用51单片机每2秒钟从DHT11温湿度传感器中读入温度和湿度&#xff0c;在液晶屏上即时显示。液晶屏上同时显示温湿度上限值&#xff0c;该上限值保存外外部EEPROM存储器中&#xff0c;掉电不失&#xff0c;并且可以通过四只按键上调或下调。当温度或湿度值超…

[猫头虎分享21天微信小程序基础入门教程]第21天:小程序的社交分享与消息推送

[猫头虎分享21天微信小程序基础入门教程]第21天&#xff1a;小程序的社交分享与消息推送 第21天&#xff1a;小程序的社交分享与消息推送 &#x1f4f2; 自我介绍 大家好&#xff0c;我是猫头虎&#xff0c;一名全栈软件工程师。今天我们继续微信小程序的学习&#xff0c;重…

MQ第②讲~保证消息可靠性

前言 上一讲我们讲了MQ实际工作中常见的应用场景&#xff0c;这一节讲一下消息的可靠性&#xff0c;如果对MQ掌握程度比较高的铁子&#xff0c;可以不用看&#xff0c;节省您宝贵的时间。 消息的大致链路 消息从投递到消费需要考虑如下几个问题 生产者的消息是否成功投递到消…

虚拟机改IP地址

使用场景&#xff1a;当你从另一台电脑复制一个VMware虚拟机过来&#xff0c;就是遇到一个问题&#xff0c;虚拟的IP地址不一样&#xff08;比如&#xff0c;一个是192.168.1.3&#xff0c;另一个是192.168.2.4&#xff0c;由于‘1’和‘2’不同&#xff0c;不是同一网段&#…

浅谈路由器转发数据包

当路由器转发数据包时&#xff0c;它会经历一系列步骤&#xff0c;包括接收数据包、路由表查询、以及转发数据包。以下是详细的步骤描述&#xff1a; 1. 接收数据包 以太网帧到达端口&#xff1a;当一个以太网帧到达路由器的某个网络接口&#xff08;端口&#xff09;时&#…

20240529瑞芯微官方Toybrick TB-RK3588开发板的Debian11下使用SCP拷贝文件

20240529瑞芯微官方Toybrick TB-RK3588开发板的Debian11下使用SCP拷贝文件 2024/5/29 20:48 1、ADB链接异常。 2、BT打开之后找不到设备&#xff1f; 不清楚&#xff1a;是我拿到的开发板的问题&#xff0c;还是Toybrick/Rockchip官方没有做好。 3、现在最新版本的WINSCP&…

154.找出出现至少三次的最长特殊字符串|(力扣)

代码解决 class Solution { public:int maximumLength(string s) {// 使用unordered_map来存储每个连续子串出现的次数unordered_map<string, int> mp;string key; // 存储当前的连续子串int ans -1; // 存储最终的答案&#xff0c;如果没有符合条件的子串&#xff0c…

高级数据结构-并查集

例题1&#xff1a; Alice和Bob玩了一个古老的游戏&#xff1a;首先画一个 &#x1d45b;&#x1d45b; 的点阵&#xff08;下图 n3 &#xff09;。 接着&#xff0c;他们两个轮流在相邻的点之间画上红边和蓝边&#xff1a; 直到围成一个封闭的圈&#xff08;面积不必为 1&#…

如何更改SSH服务器端口以减少蛮力攻击

本周有一个客户&#xff0c;购买Hostease的独立服务器&#xff0c;询问我们的在线客服&#xff0c;如何更改SSH服务器端口以减少蛮力攻击&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可以对…

8086 汇编笔记(二):寄存器(内存访问)

一、内存中字的存储 字单元的概念&#xff1a;字单元&#xff0c;即存放一个字型数据(16 位)的内存单元&#xff0c;由两个地址连续的内存单元组成 由上一章学习可知&#xff1a;高地址内存单元中存放字型数据的高位字节&#xff0c;低地址内存单元中存放字型数据的低位字节 …

扎气球最高分-第13届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第74讲。 扎气球最高分&…