C++——list的实现以及源码

前言:

最近学习了c++list的实现,这让我对迭代器的理解又上升了一个新的高度,注意:代码里的list是放在一个叫zgw的命名空间里边,但是在实现list的代码中没有加namespace,这里给个注意,以后复习时能看懂。

list的节点:

我们首先需要搞出一个list的节点,来存储数据,以及节点的下一个指针,和节点的上一个指针,STL库里边这样设计的,所以我们这样设计:

	template< class T>struct ListNode{struct ListNode<T>* _next; struct ListNode<T>* _prev;T _data;ListNode(const T& data = T())   //这里给的是匿名对象:_next(nullptr),_prev(nullptr),_data(data) {};};

设计这个节点应该是没有什么难度的。
 

包装list类:
 

template<class T>
class list
{typedef ListNode<T> node;
public:list() :_head(new node()){_head->_next = _head;_head->_prev = _head;}
private:node* _head;
};

为了让我们的list更加具有可读性,我们将,ListNode<T>重命名为node。然后我们要给一个list的无参构造,相信到现在都能看得懂。

迭代器的设计:

前方高能!!!

然后就是上强度的地方,我们需要设计list的迭代器。我们先分析一下list指针与vector的指针又什么区别呢?

首先我们list存的是ListNode<T>节点的指针,每一个新的节点都是new出来的,而且是通过指针将他们链接起来,他在物理层面上就不是连续的。

所以当我们解引用就不是一个内置类型,或者是已经设计好的自定义类型,它就没有了重载运算符,因为我们的节点就是我们自己定义的自定义类型。就算是迭代器也必要支持重载运算符。

我们举一个例子
vector的例子,当我们要搞一个存储int数据的vector容器。

void Test4()
{vector<int> v1 = { 1,2,3,4 };vector<int>::iterator it1 = v1.begin();cout << *it1 << endl;
}

这里我们是存储int内置类型,当我们解引迭代器时,实际是解引用int类型的指针,然后也支持流插入,所以可以直接打印第一个元素。
 

我后我们再想我们如果要用vector存储一个我们自己搞的一个类型,是否还支持流插入呢?

class aa
{aa(int a=10,int b=20):_a(a),_b(b){}
private:int _a;int _b;
};void Test4()
{vector<aa> v1 ;aa a1;v1.push_back(a1);vector<aa>::iterator it1 = v1.begin();cout << *it1 << endl;
}

上面这个代码会不会报错呢?当然肯定会的,为什么呢?

就是因为我们没有重载流插入。

所以通过这个例子我们应该明白了,我们ListNode本生就是一个我们自己设计的类型,所以当我们在list返回ListNode指针再解引用时肯定是不行的,因为我们没有为ListNode设计重载运算符,但是我们在这有一个新的思路我们能不能再设计一个类,当做list的迭代器,这个类迭代器存ListNode类型的指针。

在第一次听到这个设计我也是很懵逼的,都是再通过我看了两遍教学课程,再加上自己研究了一个下午,终于是领悟了其中的原理,所以想好好理解还是得自己研究。

设计的源码:


namespace zgw
{//结构体定义template< class T>struct ListNode{struct ListNode<T>* _next;struct 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                  //和引用(在这里的我们需要设计const_iterator,以及{                                     //iterator两种类型的迭代器,然后我们再通过typedeftypedef ListNode<T> node;         //封装一下,提高可读性typedef ListIterator<T,Ref,Ptr> Self;ListIterator(node*head) :_node(head){};Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}Self operator++(){_node = _node->_next;return *this;}Self operator++(int){Self re(_node);_node = _node->_next;return re;}bool operator==(const Self&node){return _node == node._node;}bool operator!=(const Self& node){return _node != node._node;}node* _node;};//封装链表,这只是一个头节点,当我们返回begin(),和end()时,//我们其实返回的是一个ListNode<T>类型的指针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;list() :_head(new node())     //当我们需要什么类型的迭代器就传对应的typedef{_head->_next = _head;_head->_prev = _head;}const_iterator cbegin(){return const_iterator(_head->_next);}const_iterator cend(){return const_iterator(_head);}iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}void push_back(const T& data){node* newnode = new node(data);node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;}iterator insert(iterator pos,const T&data){	node* cur = pos._node;node* newnode = new node(data);node* prev = cur->_prev;newnode->_next = cur;prev->_next = newnode;newnode->_prev = prev;cur->_prev = newnode;return iterator(newnode);} iterator erase(iterator pos){assert(pos != end()._node);node* cur = pos._node;node* prev=cur->_prev;node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;return iterator(next);}void pop_back(){assert(_head != begin()._node);node* tail= end()._node->_prev;node* _head = end()._node;tail->_prev->_next = _head;_head->_prev = tail->_prev;delete tail;}void pop_front(){erase(begin());}void push_front(const T&data){insert(begin(), data);}private:node* _head;};
}

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

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

相关文章

解密论文评审过程:SCI论文是匿名送审的吗?

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 前几天有位学员问我&#xff0c;审稿人能看见我论文的作者和单位信息吗&#xff1f;应该是双方都匿名才更公平啊。 同行评议&#xff0c;在不同的期刊操作还真不一样。有双方…

AI重塑保险业未来:机器学习在风险评估、欺诈检测与客户服务中的深度应用

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

linux笔记6--shell相关

文章目录 1. 查看当前的shell类型2. ps -f命令3. 父子shell4. 分号在命令里的作用问题&#xff1a;环境变量echo&#xff1a; 5. sleep和jobssleep:jobs:例子&#xff1a;&: 6. 外部命令和内建命令图解外部命令type命令 7. history命令8. alias命令9. 推荐 1. 查看当前的sh…

Midjourney Describe API 使用文档

Midjourney Describe API 使用文档 Midjourney Describe API 的主要功能是通过上传图片&#xff0c;获取对图片的描述。使用该 API&#xff0c;只需要传递图片文件&#xff0c;API 会返回图片的详细描述。无需繁琐的参数设置&#xff0c;即可获得高质量的图片描述。 支持多种图…

华为机考入门python3--(30)牛客30-字符串合并处理

分类&#xff1a;字符串、进制转换 知识点&#xff1a; 获取偶数下标的字符 even_chars my_str[::2] 获取奇数下标的字符 odd_chars my_str[1::2]) 翻转字符串 reversed_str my_str[::-1] 二进制转十进制 num int(reversed_binary, 2) 十进制转十六进制 …

JDBC使用QreryRunner简化SQL查询注意事项

QreryRunner是Dbutils的核心类之一&#xff0c;它显著的简化了SQL查询&#xff0c;并与ResultSetHandler协同工作将使编码量大为减少。 注意事项 1. 使用QreryRunner必须保证实体类的变量名&#xff0c;和sql语句中要查找的字段名必须相同&#xff0c;否则查询 不到数据,会出…

Dubbo生态之nacos

1.Nacos简介 在博客Dubbo生态之初识dubbo协议-CSDN博客种我们已经介绍了为什么要使用注册中心&#xff0c;nacos作为注册中心的一种&#xff0c;相对于其它的主流注册中心有什么区别呢? NacosEurekaZookeeper数据存储存储在内存存储在内存存储在内存通信协议gRPChttpjute协议…

[数组查找]1.图解线性查找及其代码实现

线性查找 线性查找是一种在数组中查找数据的算法。与二分查找不同&#xff0c;即便数据没有按顺序存储&#xff0c;也可以应用线性查找。线性查找的操作很简单&#xff0c;只要在数组中从头开始依次往下查找即可。虽然存储的数据类型没有限制&#xff0c;但为了便于理解&#x…

头晕、心悸…你们小年轻配不上张俊杰的霸王茶姬,还要奔上市

近日&#xff0c;有多名网友在社交平台反映称&#xff0c;自己在喝了霸王茶姬的新品“万里木兰”奶茶后&#xff0c;出现了失眠、头晕、心悸等不同程度的不适症状&#xff0c;霸王茶姬方面则表示“可能是茶多酚过敏”。 而就在几天前举行的“2024年国际茶日现代东方茶创新论坛…

揭秘 淘宝死店采集私信筛选,号称日赚500+

淘宝死店采集工具为电子商务创业者揭示了一个领域的新机遇&#xff0c;通过提供一系列深入分析和资源挖掘的功能&#xff0c;展现了从失败中寻找成功之道的独特方法论。以下是如何通过这种工具寻找电商平台中的隐含机会的几个关键方面&#xff1a; 分析失败的深层原因&#x…

一文搞懂 Transformer(总体架构 三种注意力层)

本文将从Transformer的本质、Transformer_的原理_、_Transformer的应用__三个方面&#xff0c;带您一文搞懂Transformer&#xff08;总体架构 & 三种注意力层&#xff09;。 节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友…

ISCC2024个人挑战赛WP-DLLCode

&#xff08;非官方解&#xff0c;以下内容均互联网收集的信息和个人思路&#xff0c;仅供学习参考&#xff09; 注意到程序调用了Encode函数对明文进行加密&#xff0c;点进去发现是对外部DLL的调用 静态分析DLL中的Encode函数可以得到 写出对应的解密脚本如下 #include <…

Ollama| 搭建本地大模型,最简单的方法!效果直逼GPT

很多人想在本地电脑上搭建一个大模型聊天机器人。总是觉得离自己有点远&#xff0c;尤其是对ai没有了解的童鞋。那么今天我要和你推荐ollama&#xff0c;无论你是否懂开发&#xff0c;哪怕是零基础&#xff0c;只需十分钟&#xff0c;Ollama工具就可以帮助我们在本地电脑上搭建…

2024/5/26周报

文章目录 摘要Abstract文献阅读题目创新点方法网络架构LSTM 实验过程Data acquisitionData preprocessingAlgorithm parameter settingsModels evaluation Performances of different models in indoor air temperature prediction 深度学习ARIMA一、ARIMA模型的基本思想二、AR…

遇见问题-VMware虚拟机打开运行一段时间后卡死

1.问题原因 因为Windows自带的虚拟化软件Hyper-V与VMware存在冲突。 2.关闭Hyper-V 1.打开【控制面板】-【程序和功能】-【启用或关闭Windows功能】3.关闭HV主机服务 1.右击计算机-》管理-》服务和应用名称-》服务-》找到HV主机服务-》右击属性停止服务 -》启动类型设置为禁…

英语四级翻译练习笔记①——大学英语四级考试2023年12月真题(第一套)——用ChatGPT修改训练四级翻译

目录 引言&#xff08;必看&#xff09; 翻译原文 我的翻译 得分&#xff08;1-3分&#xff09; 原文&#xff1a; 你的翻译&#xff1a; 修改后的翻译&#xff1a; 详细错误讲解&#xff1a; 引言&#xff08;必看&#xff09; 这是一篇英语四级翻译的练习的专栏&…

想转行程序员的朋友,有什么想问的在评论区随便问,我知道的都告诉你。

你想转行程序员吗&#xff1f; 我自己是法学院毕业后&#xff0c;通过2年的努力才转行程序员成功的。 我发现对于一个外行来说&#xff0c;找不到一个适合自己的方向&#xff0c;光靠努力在一个新的行业里成功异常艰难。即使你非常努力&#xff0c;但方向错了也会做大量的无用…

Java控制台实现斗地主的洗牌和发牌功能

一、题目要求 有3个玩家&#xff1a;A&#xff0c;B&#xff0c;C。底牌有三张牌&#xff0c;每个人共17张牌&#xff0c;共&#xff08;17*3354&#xff09;张牌&#xff0c;实现洗牌与发牌&#xff0c;只在控制没有实现UI可视化。 二、思路 1、用List集合存储所有的扑克牌。…

day12

第一题 本题我们可以使用以下方法&#xff1a; 方法一&#xff1a; 使用hash表<元素&#xff0c;出现次数>来统计字符串中不同元素分别出现的次数&#xff0c;当某一个元素的次数大于1时&#xff0c;返回false&#xff0c;如果每个元素的出现次数都为1&#xff0c;则返回…

【线程的互斥】

线程的互斥 临界区资源多个线程的运行多个线程对同一资源的竞争原子性保持线程之间地互斥互斥量(锁的原理)为什么是原子的 正确使用锁 临界区资源 进程创建线程&#xff0c;是共享内存的&#xff0c;可以对共享的资源有很方便的操作&#xff0c;当一些共享资源可以被多个线程进…