C++修炼之路之list模拟实现--C++中的双向循环链表

目录

引言 

一:STL源代码中关于list的成员变量的介绍

二:模拟实现list

1.基本结构

2.普通迭代器 +const迭代器的结合

3.构造+拷贝构造+析构+赋值重载 +清空

4.insert+erase+头尾插入删除 

 5.打印不同数据类型的数据《使用模板加容器来完成》

三:全部代码加测试用例链接 

接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧

引言 

在前面的数据结构中已经实现了c版本的list-双向循环链表,但在c++中注重的是分装,对于操作进行封装处理,对于我们使用便是方便了不少,但模拟实现的话还是有许多要注意的细节点,尤其是list的迭代器较复杂,需要认真理解

一:STL源代码中关于list的成员变量的介绍

在源代码中使用一个头结点的指针来 模拟实现的,但在文档中只介绍list是一个双向链表的容器,并没有说明是否带哨兵位了,之时就得观察初始化函数和构造函数等来观察

 所以从这里就可以看出list的结构就是一个带头循环双向链表,接下来我们就开始模拟实现

二:模拟实现list

1.基本结构

template<class T>//泛型编程
struct list_node
{T _data;list_node<T>* _prev;list_node<T>* _next;list_node(const T &x=T())//缺省值为匿名对象:_data(x),_prev(nullptr),_next(nullptr){}
};template<class T>
class list
{typedef list_node<T> node;
public:private:node* head;size_t size;//方便size()接口,省去便利的开销
};

2.普通迭代器 +const迭代器的结合

对于用迭代器来遍历list的数据,就不能像vector和string那样,直接使用,因为

list<int>::iterator it=lt1.begin();

while(it!=lt1.end())

{

     cout<<*it<<" ";

     ++it;

}

cout<<endl;

对于这里面的*it和++it和it!=lt1.end()这些操作是不能直接支持的,因为*it是要取data的数据,++it就是要使_node=_node->next等,这些是和vector,string是不一样的,所以得自己手动支持,运用运算符重载+函数封装,我们先来观察源代码中的实现

我们先来实现普通迭代器

 

template<class T>
struct _list_iterator
{typedef list_node<T> Node;typedef _list_iterator<T> self;Node* node;_list_iterator(Node*node):_node(node){}self& operator++(){_node = _node->next;return *this;}self& operator--(){_node = _node->prev;return *this;}self operator++(int){self tmp(*this);_node = _node->next;return tmp;}self operator--(int){self tmp(*this);_node = _node->prev;return tmp;}T& operator*(){return _node->data;}T* operator->(){return &_node->data;}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}};
template<class T>
class list
{typedef list_node<T> node;
public:typedef _list_iterator<T> iterator;iterator begin(){//return iterator(_head->_next);return _head->_next;}iterator end(){return _head;}

对于这个结构可以这样来理解

 

 我们知道const对象使用的是const迭代器那么在iterator之前加const的话,这样const iterator指的是迭代器本身不能修改,但在遍历过程迭代器本身是要改变的,如++it等,所以不能这样写

应该为const_iterator这是一个重新定义的一个类型,要做到迭代器本身可以改变,但迭代器指向的内容不能改变

在原来普通迭代器的基础上重载出一份const迭代器的版本如

但这样的话对于普通迭代器和const迭代器两份代码是由许多相同的代码的,比较冗余,所以在源代码中提出了一份更好的解决方案来解决这个问题 

在原来基础上多添加两个参数,这样对于同一个类模板,实例化参数不同就是不同的类型

对于上面的代码就要优化为更完善的代码,展示主要优化的代码

 

template<class T,class Ref,class Ptr>
struct _list_iterator
{typedef list_node<T> Node;typedef _list_iterator<T,Ref,Ptr> self;Node* node;Ref operator*(){return _node->data;}Ptr operator->(){return &_node->data;}typedef _list_iterator<T,T&,T*> iterator;typedef _list_iterator<T, const T&, const T*> const_iterator;//typedef __list_const_iterator<T> const_iterator;iterator begin(){//return iterator(_head->_next);return _head->_next;}iterator end(){return _head;}const_iterator begin()const{//return iterator(_head->_next);return const_iterator(_head->_next);}const_iterator end()const{return const_iterator(_head);}

对于->编译器是做处理的,将两个->优化为一个详细看代码及测试 用例3中

3.构造+拷贝构造+析构+赋值重载 +清空

构造时要使用带头循环双向循环链表的初始化操作,观看https://blog.csdn.net/Miwll/article/details/136593441?spm=1001.2014.3001.5502

 

void empty_init()
{_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;
}
list()
{empty_init();
}
list(const list<T>& t)//拷贝构造实现为深拷贝
{empty_init();for (auto e : t){push_back(e);}
}
/*list<int>& operator=(const list<int>& lt)
{if (this != &lt){clear();for (auto e : lt){push_back(e);}}return *this;
}*/
void swap(list<T>& t)
{std::swap(_head,t._head);std::swap(_size, t._size);
}
list<int>& operator=(const list<int>& lt)
{swap(lt);return *this;
}
~list()
{clear();delete _head;_head =nullptr;
}
void clear()
{iterator it = begin();while (it != end()){it = erase(it);}
}

4.insert+erase+头尾插入删除 

void push_back(const T& x)
{insert(end(), x);
}void push_front(const T& x)
{insert(begin(), x);
}void pop_front()
{erase(begin());
}void pop_back()
{erase(--end());
}
iterator insert(iterator pos, const T& x)
{Node* cur = pos._node;Node* newnode = new Node(x);Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return iterator(newnode);
}
iterator erase(iterator pos)
{Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;delete cur;prev->_next = next;next->_prev = prev;--_size;return iterator(next);
}
size_t size()
{return _size;
}

 5.打印不同数据类型的数据《使用模板加容器来完成》

使用模板来打印自定义类型数据,注意这里加的typename

list<T>未实例化的类模板,编译器不能去他里面去找
编译器就无法list<T>::const_iterator是内嵌类型,还是静态成员变量
前面加一个typename就是告诉编译器,这里是一个类型,等list<T>实例化
再去类里面去取

三:全部代码加测试用例链接 

https://gitee.com/lin-ciyu/cplusplus/tree/master/my_list/my_list

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

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

相关文章

python之gmsh划分网格

Gmsh&#xff08;Geometry Modeling and Meshing Suite&#xff09;是一个开源的三维有限元网格生成器&#xff0c;它集成了内置的CAD引擎和后处理器。Gmsh的设计目标是提供一个快速、轻量级且用户友好的网格工具&#xff0c;同时具备参数化输入和高级可视化能力。Gmsh围绕几何…

数据治理项目——深铁集团数据治理规划

目录 一、前言 二、数据治理内容与主要措施 2.1 实施背景 2.2 主要举措 2.2.1 制定数据战略目标 2.2.2 绘制数据治理蓝图 2.2.3 绘制数据治理制度 2.2.4 梳理数据资产目录 三、 应用效果 3.1 数据资产可视化管理 3.2 数据标准治理 3.3 集团大数据平台优化建设 一、…

Windows10为Git Bash添加文件传输命令rsync(详细图文配置)

文章目录 1. 安装git bash2. 下载所需要的4个包3. 下载解压包的软件4. 复制每个包下面的usr到git安装目录下4.1 所遇问题4.2 解决 5. 安装完成6. 需要注意 Windows上要使用 rsync命令上传或下载文件&#xff0c;需要使用git bash&#xff0c;git bash没有rsync&#xff0c;需要…

zabbix监控服务

一、监控软件的作用 作为一个运维&#xff0c;需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据去了解上线发布的结果和网站的健康状态 利用一个优秀的监控软件&#xff0c;我们可以&#xff1a; 对系统不间断实时监控实时反馈系统当前状态保…

游戏实践:扫雷

一.游戏介绍 虽然很多人玩过这个游戏&#xff0c;但还是介绍一下。在下面的格子里&#xff0c;埋的有10颗雷&#xff0c;我们通过鼠标点击的方式&#xff0c;点出你认为不是雷的地方&#xff0c;等到把所有没有雷的格子点完之后&#xff0c;及视为游戏胜利。 上面的数字的意思…

华院计算参编《金融业人工智能平台技术要求》标准

随着人工智能技术的迅猛发展&#xff0c;金融机构正在从业务场景化向企业智能化演进&#xff0c;金融业对智能化的需求愈加迫切。为引导产业有序发展、规范行业自律、加快金融行业智能化转型&#xff0c;中国信通院依托中国人工智能产业发展联盟&#xff08;AIIA&#xff09;及…

CommunityToolkit.Mvvm笔记---Ioc

使用MVVM模式提高应用程序代码库中的模块化程度的最常用模式是使用某种形式的反转控制&#xff08;Ioc&#xff09;。其中最常见的解决方案是使用依赖关系注入&#xff0c;该解决方案存在于创建多个注入后端类的服务&#xff08;即以参数的形式传递给 viewmodel 构造函数&#…

ELK+Filebeat日志分析系统

一、ELK基本介绍&#xff1a; 1.ELK 简介: ELK平台是一套完整的日志集中处理解决方案(日志系统)。 将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 ELK --> ELFK --> ELFKMQ2.ELK组件介绍…

IDEA创建jsp文件具体步骤

1. 创建普通项目 2.文件->项目结构->模块&#xff0c;点击号&#xff0c;选择web 点击确认 3.配置工件 4.配置tomcat 点击确定 5.创建jsp文件&#xff0c;注意创建位置 6.然后换调试位置 注意此时不能有其他的web项目运行,否则就选不了路径 完成后运行即可

Python代码打包成exe程序

国内镜像源 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple阿里云 https://mirrors.aliyun.com/pypi/simple/豆瓣 https://pypi.douban.com/simple/ 百度云 https://mirror.baidu.com/pypi/simple/中科大 https://pypi.mirrors.ustc.edu.cn/simple/华为云 https://mirror…

MySQL 使用C语言

一般使用MySQL很少用命令行&#xff0c;一般都是通过程序内部使用&#xff0c;MySQL也为不同的语言定制了不同的头文件和库函数&#xff0c;可以在自己的程序中通过包含头文件和编译时候链接库函数来使用MySQL。 现在一般安装MySQL的时候就会自动给你安装库函数和头文件。 可…

数据资产管理制度探索——浙江篇

在行政事业单位数据资产管理领域&#xff0c;浙江省以创新性思维与高质量发展的战略眼光&#xff0c;积极探索并构建了具有前瞻性和实效性的数据资产管理制度。作为财政部数据资产管理试点省份&#xff0c;浙江省财政厅与省标准化研究院强强联合&#xff0c;充分运用数据溯源、…

【报错】TypeError: Cannot read property ‘meta‘ of undefined

&#x1f608;解决思路 首先这里很明显我们能看到是缺少该参数&#xff1a;meta。 但是经过查找后发现和该参数无关。 &#x1f608;解决方法 后来我上网搜了下&#xff0c;网上的回答大部分偏向于是package.json这个文件中的tabBar.list数组对象只有一条的问题。 网上的大…

基于SpringBoot + Vue实现的租房管理系统设计与实现+毕业论文+开题报告​(包运行成功)

介绍 管理员的主要功能设计为&#xff1a;密码信息管理、注册用户管理、区域管理、出租管理等模块。 房主的主要功能设计为&#xff1a;密码信息管理、个人信息管理、订单管理等模块。 用户的主要功能设计为&#xff1a;用户登录、密码管理、出租管理、收藏管理等模块。 源码论…

数据结构---线性表

1&#xff0c;顺序表实现---动态分配 #include<stdlib.h> #define InitSize 10 typedef struct {int *data;//静态分配int length;int MaxSize; }SqList; void InitList(SqList& L) {L.data (int*)malloc(InitSize * sizeof(int));//分配空间L.length 0;L.MaxSize…

关于SpringCloud,你了解多少?

Why SpringCloud&#xff1f; Spring cloud 是一系列框架的有序集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用 spring boot 的开发风格做到一…

论坛直击|发展新质生产力,高校怎么做?

新质生产力浪潮涌动 三大议题聚焦高校人才培养 今年全国两会的政府工作报告将“大力推进现代化产业体系建设&#xff0c;加快发展新质生产力”列在2024年政府工作任务首位&#xff0c;发展新质生产力的先导是培养拔尖创新人才&#xff0c;高等教育改革必须以立德树人为根本任…

带你从BIOS 小工到年薪百万 之 sense amplifier 的作用以及MRC 如何初始化它

做过BIOS 的同学&#xff0c;肯定看过这张图片 对世界充满好奇心的你&#xff0c;是否想过 其中 Sense amplifier 是做什么用的&#xff1f; 是如何工作的&#xff1f; BIOS 又是如何训练它的&#xff1f; 明天接着写

分布式的计算框架之Spark(python第三方库视角学习PySpark)

基本介绍 Apache Spark是专为大规模数据处理而设计的快速通用的计算引擎 。现在形成一个高速发展应用广泛的生态系统。 特点介绍 Spark 主要有三个特点&#xff1a; 首先&#xff0c;高级 API 剥离了对集群本身的关注&#xff0c;Spark 应用开发者可以专注于应用所要做的计…

transformer在生物基因DNA的应用:DNABERT、DNABERT-2

参考&#xff1a; https://www.youtube.com/watch?vmk-Se29QPBA&t1388s 写明这些训练模型可以最终训练好可以进行DNA特征向量的提取&#xff0c;应用与后续1、DNABERT https://github.com/jerryji1993/DNABERT 主要思路就是把DNA序列当成连续文本数据&#xff0c;直接用…