C++初阶之list的使用和模拟以及反向迭代器的模拟实现

个人主页:点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶    算法

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

一.list简介

        list是一个带头双向链表,在数据结构的时候,我写过关于带头双向循环链表的实现,可以看博客https://yangking.blog.csdn.net/article/details/134495668,我们可以看下面的图,是list的存储结构,

本次的内容包括list的使用,list的模拟实现,list的迭代器以及反向迭代器的原理,模拟实现和使用,最重要的是迭代器和反向迭代器的内容,在前面string和vector中迭代器是原生的指针,但是在这里不是,具体是什么样子的我们可以看后面的内容。 

二.一个简易的list

2.1.单个节点

template<class T>
struct ListNode
{typedef  ListNode<T>  Node;Node* _next;Node* _prev;T _data;ListNode(const T& val = T()): _next(nullptr), _prev(nullptr), _data(val){}
};

在这里我们可以使用strcut结构体来创建一个节点

2.2.默认构造

void empty_init()
{_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;
}
list()
{empty_init();
}

我们创建一个头节点, 让它指向自己。

2.3push_back

void push_back(const T& val)
{Node* newnode = new Node(val);Node* prev = _head._node->_prev;Node* cur = _head._node;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;_size++;
}

在这里我们就是简单的插入操作,不给具体的解释。到这里我们简易的list就完成了,我们依次插入1234可以看到

void test()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);
}

三.迭代器

        我们封装一个迭代器的类,我们的迭代器需要支持

list<int>::iterator it = lt1.begin();
while (it != lt1.end())
{cout << *it << " ";++it;
}
cout << endl;

所以我们里面需要包括!=,*it,++it,以及begin和end这些内容,我们需要知道迭代器模仿的是Node*这个行为,我们看一下模拟代码:

template <class T>
struct ListIterator
{typedef ListNode<T>  Node;typedef ListIterator<T> Self;Node* _node;ListIterator(Node* node):_node(node){}bool operator==(const Self& it){return _node == it._node;}bool operator!=(const Self& it){return _node != it._node;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self tmp(_node);_node = _node->_prev;return *tmp;}Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(_node);_node = _node->_next;return tmp;}T& operator*(){return _node->_data;}
};

我们在list类里面加入

iterator begin()
{return _head->_next;
}
iterator end()
{return _head;
}

我们运行测试代码

void test()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);list<int>::iterator it = l.begin();while (it != l.end()){cout << *it << " ";it++;}cout << endl;
}

运行结果为

四.insert和erase以及复用

4.1insert

 在这里我们的insert用迭代器进行插入,给以个位置,插入它的前面,

 我们的代码如下:

void insert(iterator pos, const T& val)
{Node* newnode = new Node(val);Node* prev = pos._node->_prev;Node* cur  = pos._node;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;_size++;
}

有了我们的insert我们的push_back可以复用我们的insert,可以改为

void push_back(const T& val)
{insert(end(), val);
}

在这里我们的insert不会造成迭代器失效,因为指针指向的位置不会发生改变,它是插入到pos位置的前面。

4.2erase以及迭代器失效

对于返回值为什么是iterator,这和我们的迭代器失效有关,我们先用void来展示其中的问题。

void erase(iterator pos)
{Node* prev = pos._node->_prev;Node* next = pos._node->_next;delete pos._node;prev->_next = next;next->_prev = prev;_size--;
}

我们的测试代码如下:
 

void test()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);list<int>::iterator it = l.begin();while (it != l.end()){if (*it % 2 == 0) l.erase(it);else it++;}it = l.begin();while (it != l.end()){cout << *it << " ";it++;}cout << endl;
}

在这里会出现错误,原因是迭代器失效,野指针的引用,所以我们需要对迭代器进行维护,所以有了返回值,我们改为

iterator erase(iterator pos)
{Node* prev = pos._node->_prev;Node* next = pos._node->_next;delete pos._node;prev->_next = next;next->_prev = prev;_size--;return next;
}

4.3复用

有了这两个,我们的pop_back,pop_front,push_front就可以有了

void pop_back()
{erase(--end());
}
void pop_front()
{erase(begin());
}
void push_front(const T& val)
{insert(begin(), val);
}

五.operator->()

        我们的T是一个结构体

struct A
{int a = 1;int b = 2;
};
void test()
{list<A> l;l.push_back({ 1,2 });l.push_back({ 2,3 });l.push_back({ 3,4 });l.push_back({ 4,5 });list<A>::iterator it = l.begin();while (it != l.end()){/*	cout << (*it).a << " " << (*it).b << endl;*/cout << it._node->_data.a << " " << it._node->_data.b << endl;it++;}
}

 我们的解引用是不是看的非常难受,所有我们需要operator一下,

T* operator->()
{return &_node->_data;
}

 我们改为

cout << it->a << " " << it->b << endl;

六.const迭代器

        有了我们的非const版本的,那么我们就需要我们的const版本的,const版本就是将所有的都复制一份,然后operator*返回const的

template <class T>
struct ListConstIterator
{typedef ListNode<T>  Node;typedef ListConstIterator<T> Self;Node* _node;ListConstIterator(Node* node):_node(node){}bool operator==(const Self& it){return _node == it._node;}bool operator!=(const Self& it){return _node != it._node;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self tmp(_node);_node = _node->_prev;return *tmp;}Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(_node);_node = _node->_next;return tmp;}const T& operator*(){return _node->_data;}const T* operator->(){return &_node->_data;}
};

由于这个会和非fonst很多内容一样,会造成代码冗余,所以我们可以利用模板来简化我们的代码,我们非const的代码函数的返回值为Self,T&,T*,const版本的是Self,const T&,const T*,所以我们可以写成模板

template <class T,class Ref,class Ptr>
struct ListIterator
{typedef ListNode<T>  Node;typedef ListIterator< T, Ref, Ptr> Self;Node* _node;ListIterator(Node* node):_node(node){}bool operator==(const Self& it){return _node == it._node;}bool operator!=(const Self& it){return _node != it._node;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self tmp(_node);_node = _node->_prev;return *tmp;}Self& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(_node);_node = _node->_next;return tmp;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}
};

我们在list类里面写入

typedef ListIterator<T,T&,T*> iterator;
typedef ListIterator<T,const T&,const T*> const_iterator;

这样我们由我们自己写改为了编译器去写。

七.反向迭代器

        我们的反向得带起是使用正向迭代器进行写的,它的rbegin是正向迭代器的end,rend是正向迭代器的begin,所以它的operator*是解引用前一个的。

template <class Iterator, class Ref, class Ptr>
struct ReverseIterator
{typedef ReverseIterator<Iterator, Ref, Ptr> Self;Iterator _it;ReverseIterator(Iterator it):_it(it){}Ref operator*(){Iterator tmp = _it;--tmp;return *tmp;}Ptr operator->(){return _it.operator->();}Self rbegin(){return ReverseIterator(_it.end());}Self rend(){return ReverseIterator(_it.begin());}Self operator++(){--_it;return *this;}Self operator++(int){Iterator tmp = _it;--_it;return tmp;}Self operator--(){++_it;return *this;}Self operator--(int){Iterator tmp = _it;tmp = _it;++_it;return tmp;}bool operator!=(Self it){return _it != it._it;}};

到这里我们的内容结束了。

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

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

相关文章

不必追求深度,浅尝辄止为宜

近日笔者撰文称&#xff0c;有幸应《百度-百家号》相邀&#xff0c;在其发起的《征文任务》栏目中写作深度文章&#xff0c;便试着开头写了一篇《万科有“活下去”的可能性吗&#xff1f;》的时评文章&#xff0c;于5月3日发表&#xff0c;舆情反映不错&#xff0c;不到三天时间…

python菜鸟级安装手册

python安装教程 电脑-右键-属性&#xff0c;确认系统类型和版本号&#xff0c;比如本案例系统是64位 win10 点击python官网&#xff0c;进行下载 适用于 Windows 的 Python 版本 |Python.org 选择第一个安装程序64位即可满足需要&#xff0c; 嵌入式程序包是压缩包版本&…

JavaScript中的RegExp和Cookie

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;JavaScript 精粹 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 &#x1f506;RegExp &#x1f3b2; 1 什么是正则表达式 &#x1f3b2;2 创建…

山东省文史书画研究会成立20周年系列活动徽标征集胜选名单公布

2024年5月1日&#xff0c;山东省文史书画研究会成立20周年系列活动徽标征集落下帷幕。征稿启事下发后&#xff0c;得到社会各界人士的广泛关注与参与&#xff0c;共收到设计方案608件。经过初评&#xff0c;选出5幅作品进入复评&#xff0c;并经过网络投票和专家投票相结合的方…

颗粒精炼剂可用于铝及铝合金熔铸工艺中 我国生产企业众多

颗粒精炼剂可用于铝及铝合金熔铸工艺中 我国生产企业众多 颗粒精炼剂指外观呈白色粉末状或颗粒状&#xff0c;可用于金属颗粒表面处理的重要化学药剂。颗粒精炼剂具有反应速度快、绿色环保、安全稳定性好等优势&#xff0c;在铝及铝合金的熔铸工艺中应用较多。按照钠含量不同&a…

有关string的部分接口

1.迭代器与反向迭代器(iterator-) 迭代器是可以用来访问string里面的内容的&#xff0c;这里来记录一下使用的方法。 里面用到了一个叫做begin函数和一个end函数&#xff0c;这两个都是针对string使用的函数。 s1.begin()函数是指向string内容的第一个元素 而s1.end()指向的则…

每日OJ题_贪心算法三②_力扣553. 最优除法

目录 力扣553. 最优除法 解析代码 力扣553. 最优除法 553. 最优除法 难度 中等 给定一正整数数组 nums&#xff0c;nums 中的相邻整数将进行浮点除法。例如&#xff0c; [2,3,4] -> 2 / 3 / 4 。 例如&#xff0c;nums [2,3,4]&#xff0c;我们将求表达式的值 "…

滑块验证码说明

滑块验证码说明 滑块验证码 旋转验证码 滑动还原验证码 文字点选验证码 快速上手 注意: 如果你项目是使用的Springboot&#xff0c; 请使用SpringBoot脚手架工具tianai-captcha-springboot-starter; 该工具对验证码进行了封装&#xff0c;使其使用更加方便快捷 后端说明 引…

深度学习之基于Matlab Googlenet网络男女性别识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着计算机视觉技术的快速发展&#xff0c;性别识别在多个领域中都展现出了广泛的应用前景&#xff…

【Unity】如何获得TMP Button下的text内容

【背景】 unity项目中使用了TMP命名空间的Button UI组件。脚本中需要获得Button下Text的内容,但是发现用TextMeshPro仍然无法获得button下的text对象。 【分析】 Hierarchy结构上看明确Button下是有Text组件的: 括号里是TMP,所以理论上用TextMeshPro类型去FindComponent…

“A”分考试经验分享:云计算HCIE考试请注意这几点...

大家好&#xff0c;我是誉天云计算HCIE的王同学&#xff0c;于4月2日"A"分通过了云计算3.0 HCIE的认证考试。 首先感谢誉天教育对我的辅导&#xff0c;感谢苗苗老师和石老师对我的帮助&#xff0c;通过这次考试让我对华为云计算有了一定的了解。接下来我就与大家分享…

GOG平台账号注册教程 内附GOG平台官网地址

GOG平台账号注册教程 内附GOG平台官网地址 GOG平台不知道大家听没听说过&#xff0c;该平台也是一款游戏平台&#xff0c;上面还是有着不少的游戏的&#xff0c;尤其是该平台的福利活动特别多&#xff0c;经常会免费发放一些游戏&#xff0c;这个7月份的话就有两款游戏现在是…

聊聊 ASP.NET Core 中间件(二):中间件和筛选器的区别

前言 有些小伙伴看到上一篇文章后&#xff0c;可能会发现中间件和我们之前讲的筛选器非常类似&#xff0c;比如它们都是通过 next 串起来的一系列的组件&#xff0c;并且都可以在请求处理前后执行代码&#xff0c;都可以通过不执行 next 来进行请求的终止。那么筛选器和中间件…

400G光模块产品最全分类解析

随着信息技术的迅猛发展&#xff0c;网络带宽需求不断增加&#xff0c;而400G光模块作为当前最热门的光通信技术之一&#xff0c;正在成为新一代网络的关键组成部分。本文将对400G光模块进行最全面的分类解析&#xff0c;以帮助大家深入了解其技术特点和应用场景。 一、ETU-LI…

轻松驾驭teamOS审批流程,权限提升秘诀:teamOS审批功能详解与实战指南

大家在日常办公时&#xff0c;是否有遇到过这样的情况&#xff1a;在进行协作的时候&#xff0c;需要在项目组中发布文档&#xff0c;但当前并没有这个权限。正常走审批流程&#xff0c;可能需要花费一定的时间。 teamOS&#xff0c;一键发起审批流程 在企业的日常运营中&…

FMEA助力智能电网升级:构建安全、高效、可靠的电力网络

随着科技的不断进步&#xff0c;智能电网已成为现代电力行业的重要发展方向。而在这个过程中&#xff0c;FMEA&#xff08;失效模式和影响分析&#xff09;作为一种重要的质量管理工具&#xff0c;正日益发挥着其在智能电网建设中的赋能作用。本文将从FMEA的基本概念出发&#…

Java基础(三):Java异常机制以及底层实现原理

&#x1f337;一、异常 ☘️1.1 什么是异常 Java异常是程序发生错误的一种处理机制&#xff0c;异常的顶级类是Throwable&#xff0c;Throwable字面意思就是可抛出的&#xff0c;该类是所有的错误和异常的超类&#xff0c;只有Throwable类或者Throwable子类的实例对象才可以被…

缓存菜品操作

一&#xff1a;问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大。 二&#xff1a;实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; 每个分…

ACWing-186巴士-DFS

题目 原题链接&#xff1a;186. 巴士 - AcWing题库 oj:xmuoj | 最小化蒙德城的旅行者队伍 思路 本题因为n300&#xff0c;说明搜索深度很深&#xff0c;但是测试数量小于17&#xff0c;所以答案一定在比较浅的一个搜索深度中&#xff0c;于是可以利用迭代加深的处理方法迭代…

基于Springboot+Vue的Java项目-旅游网站系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…