c++——list实现细节反思

list实现反思

Mystl

list实现

一开始没有什么好注意的,直接写就行了。


先写节点和list类
	template<class T>struct ListNode{T _val;ListNode<T>* _next = nullptr;ListNode<T>* _pre = nullptr;//ListNode() {}ListNode(const T& val = T()){//默认构造:无参,全缺省,不写编译器自动生成//三者只能存在一个_val = val;}};class list{public:typedef ListNode<T> Node;typedef ListNode<T>* PNode;//不要动不动就是用iteratorvoid empty_init(){_head = new Node;_head->_pre = _head->_next = _head;}list(){empty_init();}private:PNode _head = nullptr;size_t _size = 0;
};

默认构造:无参,全缺省,不写编译器自动生成,三个只能有一个,我们更喜欢使用全缺省参数的默认构造函数
链表中加入一个size,在计算链表长度的时候可以在0(1)的时间复杂度之内得到
我们让头指针指向一个哨兵的头节点


元素插入和删除
		void push_back(const T& val = T()){PNode node = new Node(val);PNode pre = _head->_pre;pre->_next = node;node->_next = _head;_head->_pre = node;node->_pre = pre;_size++;}void pop_back(){assert(_size);PNode tem = _head->_pre;PNode pre = _head->_pre->_pre;pre->_next = _head;_head->_pre = pre;delete tem;}void push_front(const T& val){//不能给一个缺省值,这个函数要严格限制传入的数据,不传入就不能使用这个函数PNode node = new Node(val);PNode next = _head->_next;next->_pre = node;node->_pre = _head;_head->_next = node;node->_next = next;_size++;}

在实现插入函数的时候一定不能给一个缺省参数,如果给了默认参数,在没有传值的时候,就成了一个无参的调用,这不是扯呢吗,插入一定不能给默认参数


迭代器

先不要急着实现const_iterator

先分析迭代器需不需要,能不能像vector直接typedef一个iterator
iterator要能++,++是向后走到下一个节点,那么就不能将指针typedef成iterator
iterator要能进行++,–,==,!= ,这都是要对iterator进行操作,那么就要是现成一个类进行重载

	template<class T>struct ListIterator{private:typedef ListNode<T> Node;typedef ListNode<T>* PNode;typedef ListIterator<T,Ref,Ptr> iterator;public:ListNode<T>* _cur;ListIterator(ListNode<T>* val){_cur = val;}iterator& operator++(){_cur = _cur->_next;return *this;}iterator& operator--(){_cur = _cur->_pre;return *this;}iterator operator++(int){iterator tem = _cur;_cur = _cur->_next;return tem;}iterator operator--(int){iterator tem = _cur;_cur = _cur->_pre;return tem;}bool operator==(const iterator& tem){return _cur == tem._cur;}bool operator!=(const iterator& tem){return _cur != tem._cur;}T& operator*(){//接引用返回的是这个对象本身//返回的是内容的地址,但是在使用的时候就可以直接使用这儿内容了return _cur->_val;}T* operator->(){//->返回的是这个地址//return &_cur;//应该不能返回地址的地址吧//使用-> 操作符,得到空间的地址,然后使用//但是有点儿想不懂啊,为什么->返回的是地址,在使用的时候就可以直接找到他的空间中的对象了呢//->隐藏了一个->return &_cur->_val; }};

operator*是解引用,返回的是他的元素本身
operator->也是解引用,按照一般的使用习惯应该是lt->_val,如果像平常的时候方法重载的话就有点儿不知道重载的括号中的参数怎么传了,但是解引用之后返回的是什么东西呢
重载->的时候很怪,因为编译器进行了优化,他的原型是lt.operator->()->_val本身应该使用这种访问方式,中间隐藏掉了一个->


现在我们只要在list中实现begin和end就可以进行范围遍历

		typedef ListIterator<T> iterator;iterator begin(){return _head->_next;}iterator end(){return _head;}
		T& front(){assert(_head != _head->_next);return (_head->_next->_val);}T& back(){assert(_head != _head->_pre);return _head->_pre->_val;}const T& front() const {assert(_head != _head->_next);return (_head->_next->_val);}const T& back() const {assert(_head != _head->_pre);return _head->_pre->_val;}

功能函数
		iterator insert(iterator pos, const T& val){// 在pos位置前插入值为val的节点PNode pre = pos._cur->_pre;PNode node = new Node(val);PNode next = pos._cur;next->_pre = node;node->_pre = pre;pre->_next = node;node->_next = next;_size++;return pre;//返回新的位置}iterator erase(iterator pos){//删除某个位置,返回下一个位置PNode cur = pos._cur;;PNode pre = pos._cur->_pre;PNode next = pos._cur->_next;pre->_next = next;next->_pre = pre;delete cur;return next;}void clear(){//for (auto it = begin(); it != end(); it++)//{//	//erase(it);//把这个节点删除之后,it还在这个节点上,使用it++会发生迭代器失效//	//需要重新更正迭代器位置//}auto it = begin();while (it != end())it = erase(it);//会自动跳转}

在使用clear调用erase的时候要注意迭代器要向后转移


构造和析构
		list(int n, const T& val = T()){empty_init();//每一个都要使用empty_init进行初始化for (int i = 0; i < n; i++)push_back(val);}template <class Iterator>list(Iterator first, Iterator last){empty_init();while (first != last){push_front(*first);first++;}}list(const list<T>& l){empty_init();for (auto e : l)push_back(e);}void swap(list<T>& lt){std::swap(this->_head, lt._head);std::swap(this->_size, lt._size);}list<T>& operator=(list<T> lt){empty_init();swap(lt);return *this;}~list(){clear();delete _head;}

const_iterator实现分析

const_iterator 实现效果是内容不可改,指向可以改(因为需要const_iterator进行++)
目标是实现成const T* 这种效果
const iterator const修饰的是iterator的值,如果修饰的是iterator的值,那就不能使用++
所以需要iterator const,但是这种也是不对的,iterator 可以看成是一个类型iterator const = const iterator就像const int 和int const的道理一样
我们没有一个直接加const的方法来达到目的,所以我们只能要实现一个const_iterator类
我们可以使用iterator的大部分函数来重写const_iterator
那既然有那么多相同的部分,能不能进行复用

	template<class T,class Ref,class Ptr>struct ListIterator{private:typedef ListNode<T> Node;typedef ListNode<T>* PNode;typedef ListIterator<T,Ref,Ptr> iterator;public:ListNode<T>* _cur;ListIterator(ListNode<T>* val){_cur = val;}iterator& operator++(){_cur = _cur->_next;return *this;}iterator& operator--(){_cur = _cur->_pre;return *this;}iterator operator++(int){iterator tem = _cur;_cur = _cur->_next;return tem;}iterator operator--(int){iterator tem = _cur;_cur = _cur->_pre;return tem;}bool operator==(const iterator& tem){return _cur == tem._cur;}bool operator!=(const iterator& tem){return _cur != tem._cur;}//PNode& operator->()//{//	return _cur;//}//T* operator*()//{//	return &_cur->_val;//}Ref operator*(){//接引用返回的是这个对象本身//返回的是内容的地址,但是在使用的时候就可以直接使用这儿内容了return _cur->_val;}Ptr operator->(){//->返回的是这个地址//return &_cur;//应该不能返回地址的地址吧//使用-> 操作符,得到空间的地址,然后使用//但是有点儿想不懂啊,为什么->返回的是地址,在使用的时候就可以直接找到他的空间中的对象了呢//->隐藏了一个->return &_cur->_val; }};typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T,const T&,const T*> const_iterator;

template<class T,class Ref,class Ptr>多传了两个类型就能够实现复用了

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

传的是const类型的参数,得到的就是const类型的iterator;传的是普通类型,得到的就是普通的iterator,在类中还要写一个构造函数,在begin返回到时候需要进行类型转换

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

要将指针转换为iterator
*只能对内置数据类型使用,对自定义数据类型不能使用
内置数据类型如何进行输出?
一般情况下是不会将输出流进行重载,因为如果重载了,输出的形式就固定了,不好
对于这种情况,没有什么好的方法


补充

如果想写一个模板,进行输出

	template<typename T>void printList(const list<T>& lt){//list<T>:;这种访问方式可以是静态成员,也可以是内嵌类型// 在类型未确定时,它是不会到类中寻找的//这里必须要加上typename进行修饰,告诉编译器这是一个类型,要等到类型确定之后再去类中寻找typename list<T>::const_iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";it++;}puts("");}

list<T>::这种访问方式可以是静态成员,也可以是内嵌类型
在类型未确定时,它是不会到类中寻找的
这里必须要加上typename进行修饰,告诉编译器这是一个类型,要等到类型确定之后再去类中寻找

介绍这种情况可不是让各位去用,这种输出的方法不是好方法,而是让各位知道在类型未确定的时候要加typename关键字进行修饰,告诉编译器,等类型确定之后再去找

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

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

相关文章

【Kubernetes】kubectl 常用命令

kubectl 常用命令 1.基础命令2.部署命令3.集群管理命令4.故障诊断与调试命令5.高级命令6.设置命令7.其他命令 kubectl 是 Kubernetes 提供的命令行管理工具。通过使用 kubectl&#xff0c;可以管理和操作 Kubernetes。 1.基础命令 命令 说明 create通过文件名或标准输入创建 …

Java Object浅克隆深克隆

对象克隆 把A对象的属性值完全拷贝给B对象&#xff0c;也叫对象拷贝&#xff0c;对象复制。 实现Cloneable接口&#xff0c;表示当前类的对象就可以被克隆&#xff0c;反之&#xff0c;表示当前类的对象就不能克隆。 如果一个接口里面没有抽象方法&#xff0c;表示当前的接口…

VCG 基于CMake构建VCG项目

文章目录 一、简介二、相关配置三、实现代码四、实现效果参考资料一、简介 VCGlib(Visual Computing Library)是一个开源的C++库,专注于提供用于处理和分析三维图形的工具和数据结构。VCGlib 主要用于计算机图形学、计算机辅助设计(CAD)、计算机视觉等领域。以下是关于 VC…

LangChain(0.0.340)官方文档十一:Agents之Agent Types

LangChain官网、LangChain官方文档 、langchain Github、langchain API文档、llm-universe《Agent Types》、《Examples using AgentType》 文章目录 一、快速入门1.1 概念1.2 基本示例1.2.1 配置LangSmith1.2.2 使用LCEL语法创建Agents1.2.3 使用自定义runtime执行1.2.4 使用A…

CentOS 7 实战指南:文件操作命令详解

写在前面 想要快速掌握 CentOS 7 系统下的文件操作技巧吗&#xff1f;不用担心&#xff01;我为你准备了一篇详细的技术文章&#xff0c;涵盖了各种常用的文件操作命令。无论您是初学者还是有一定经验的用户&#xff0c;这篇文章都能帮助您加深对 CentOS 7 文件操作的理解&…

MySQL基础入门(二)

多表内容 一对多 这个内容是黑马的入门问题&#xff0c;可以带大家思考一下这个怎么设计 我们要知道一个岗位可以对应很多用户&#xff0c;而一个用户只能对应一个岗位&#xff0c;这就属于一对多的类型 那么我们需要怎么将他们进行关联呢&#xff1f; 现在我们可以通过一个…

【OpenAI Q* 超越人类的自主系统】DQN :Q-Learning + 深度神经网络

深度 Q 网络&#xff1a;用深度神经网络&#xff0c;来近似Q函数 DQN&#xff08;深度 Q 网络&#xff09; 深度神经网络 Q-LearningQ-Learning模型结构损失函数经验回放探索策略流程关联 DQN 优化DDQN&#xff1a;双 DQN&#xff0c;实现无偏估计Dueling DQN&#xff1a;提高…

面试数据库八股文五问五答第四期

面试数据库八股文五问五答第四期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;什么情况下 mysql 会索引失效&#xff1f; 不使用索引列进行查询&a…

Quartus的Signal Tap II的使用技巧

概述&#xff1a; Signal Tap II全称Signal Tap II Logic Analyzer&#xff0c;是第二代系统级调试工具&#xff0c;它集成在Quartus II软件中&#xff0c;可以捕获和显示实时信号&#xff0c;是一款功能强大、极具实用性的FPGA片上调试工具软件。 传统的FPGA板级调试是由外接…

某大型车辆检测维修公司降本增效项目纪实

【客户行业】车辆检测维修 【问题类型】降本增效 【客户背景】 某大型车辆检测维修公司成立于2007年&#xff0c;位于我国河南省&#xff0c;占地面积26亩&#xff0c;是某大型国有企业下属的分公司&#xff0c;业务范围涉及汽车年检及检测、汽车修理、保险理赔、汽车装饰等…

ROS学习记录:用C++实现对wpr_simulation软件包中机器人的运动控制

一、在工作空间下输入catkin_make进行编译 二、在工作空间中输入source ./devel/setup.bash后回车 三、机器人的运动控制在wpr_simulation中有一个例子程序&#xff0c;在工作空间中输入&#xff1a; roslaunch wpr_simulation wpb_simple.launch后回车 四、就会启动一个仿真环…

菜鸟网络Java实习一面面经

自我介绍&#xff0c;做过的项目 巴拉巴拉 你项目中用到redis&#xff0c;可以介绍一下为什么使用它吗&#xff1f; 基于内存操作&#xff0c;内存读写速度快。 支持多种数据类型&#xff0c;包括String、Hash、List、Set、ZSet等。 支持持久化。Redis支持RDB和AOF两种持久…

Transformer基本结构

Transformer基本结构 输入部分、编码部分、解码部分、输出部分 1、输入部分 原文本嵌入层及其位置编码器目标文本嵌入层及其位置编码器 位置编码器(PositionalEncoding)&#xff1a;将词汇位置不同可能会产生不同语义的信息加入到词张量中&#xff0c;以弥补位置信息的缺失 …

Win10 + 4090显卡配置深度学习环境 + gaussian-splatting配置 + 实测自己的场景

目录 1 安装Anaconda 2023.09版本 2 安装CUDA11.8 3 安装深度学习库Cudnn8.6.0 4 安装VSCODE2019 5 安装Colmap3.8 6 安装git 7 安装Python3.10 Pytorch2.0.0 7 安装项目 8 采集数据 8.1 IPhone 14 pro 拍摄30张照片左右 做预处理 8.2 生成colmap位姿等信息 8.3 开…

STM32——F407定时器概述

1 定时器分类 定时器类型数量位号位宽时钟捕获/比较输出DMA请求计数互补输出基本2TIM6,TIM716bitAPB1-有递增-通用2TIM2,TIM532bitAPB14通道有递增、递减、中心对齐-通用2TIM3,TIM432bitAPB14通道有递增、递减、中心对齐-通用1TIM916bitAPB14通道有递增-通用2TIM10、TIM1116bi…

独立站的营销策略:吸引顾客的秘密武器

一、独立站的重要性 独立站是指企业自主建立的电子商务网站&#xff0c;具有独立的域名和运营管理权。通过独立站&#xff0c;企业可以展示产品信息、提供在线服务、进行促销活动等&#xff0c;与顾客建立互动和信任关系。独立站的重要性在于它可以帮助企业建立品牌认知度、提…

面向对象基础-类与对象-封装

1、类与对象 1.1 概念 类&#xff1a;类是一个抽象的概念&#xff0c;用于描述一类对象的特点。 对象&#xff1a;根据类的概念所创造的实体。 【思考】一个对象可以没有对应的类嘛&#xff1f; 不可以&#xff0c;因为必须现有类才能创建对象。 1.2 类的内容 类中最基础的内容…

pygame学习(一)——pygame库的导包、初始化、窗口的设置、打印文字

导语 pygame是一个跨平台Python库(pygame news)&#xff0c;专门用来开发游戏。pygame主要为开发、设计2D电子游戏而生&#xff0c;提供图像模块&#xff08;image&#xff09;、声音模块&#xff08;mixer&#xff09;、输入/输出&#xff08;鼠标、键盘、显示屏&#xff09;…

maven中dependencyManagement标签

简介 dependencyManagement正如其名&#xff0c;用于项目依赖的统一管理。 在父项目中的pom.xml文件中加入dependencyManagement标签即可完成依赖版本的声明。在声明完成后&#xff0c;子项目&#xff08;module&#xff09;中引用相同的依赖时可以不指定version标签自动引入…

【26.4K⭐】ShareX:一款开源免费、功能强大且丰富的截屏录屏软件

【26.4K⭐】ShareX&#xff1a;一款开源免费、功能强大且丰富的截屏录屏软件 在日常工作、学习和娱乐过程中&#xff0c;我们经常需要截取屏幕或者录制屏幕上特定区域中的内容并进行标记、编辑等操作。无论是为了记录重要的信息、分享有趣的内容&#xff0c;还是为了制作教程和…