C++学习之list的实现
在了解学习list实现之前我们首先了解一下关于迭代器的分类:
按功能分类:
正向迭代器 反向迭代器
const正向迭代器 const反向迭代器
按性质分类:
单向迭代器 只能++ 例如单链表
双向迭代器 可++,也可-- 例如双链表 ,map和set
随机迭代器 可加加,可减减,可+,可减 如顺序表(vector string),deque(双端队列)
这些都是由容器的底层实现。

可以看到库中提供的list模板是带头双向链表,故此我们实现它就大部分操作都是在数据结构中实现双链表时是一样。
目录
1.成员变量
节点类型的定义:
迭代器
重载前置++/--
重载后置++/--
重载*与->
重载!=与==
const迭代器
迭代器的优化:
成员函数
构造函数
析构函数
拷贝构造函数
容量
size
修饰符
insert()
erase ()
push_front()
pop_front()
push_back()
pop_back()
clear()
1.成员变量
template<class T>class mylist{typedef list_node<T> Node;typedef _list_iterator<T, T&, T*> iterator;typedef _list_iterator<T,const T&,const T*> const_iterator;
private:Node* _head;size_t _size;
......
}
因为实现的是链表,故此我们的成员变量是链表头节点与链表的大小,这里我们还需要给出
节点类型的定义:
typedef list_node<T> Node;
template<class T>struct list_node{//我们给一个缺省值为T的匿名对象list_node(const T& x = T()):data(x), _next(nullptr), _prev(nullptr){}T data;list_node<T>* _next;list_node<T>* _prev;};
迭代器
因为我们实现的是链表,那么迭代器的操作也就是链表节点的操作,节点并非一般的数据类型,
故此我们这里需要封装迭代器,迭代器本质是节点的地址:
//迭代器//认真思考的话,迭代器模拟的是一个双链表节点的运动,故我们封装迭代器里面一定是节点,这里放入节点的地址//并且重载对应的运算符,封装之后,我们在定义为iteratortemplate<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;}
const迭代器
const迭代器对应const对象,指的是内容不能被修改,而非指针(迭代器)本身,因此我们不能直接const iterator去认为是const迭代器,这样反而不能对迭代器进行++等操作,而需要我们去重新定义
定义const迭代器,即内容是无法被修改,由于我们访问内容是通过解引用的方法故我们需要修改访问的的这两个操作符其引用返回为const,即内容无法被修改了。
template<class T>struct _list_const_iterator{typedef list_node<T> Node;typedef _list_const_iterator<T> self;Node* _node;_list_const_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;}const T* operator->(){return &_node->data;}const T& operator*(){return &_node->data;}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}};
由于const迭代器与普通的迭代器区别也就在于访问的内容无法被修改,也就是修改*与->这两个访问内容的操作符,重新实现较为麻烦,库中实现是增加了两个模板参数Ref,Ptr,利用我们传的参数不一样,从而决定用的是哪一个迭代器。
迭代器的优化:
多出两个模板参数之后,我们的*与->返回类型就是到时候传入时候的类型,故这里我们直接用Ref与Ptr代替即可。
template<class T,class Ref,class Ptr>struct _list_iterator{//利用节点的指针实现迭代器typedef list_node<T> Node;typedef _list_iterator<T,Ref,Ptr> self;Node* _node;_list_iterator(Node* node):_node(node){}
}
Ptr operator->(){return _node->data;}Ref operator*(){return &_node->data;}
在list中,对于模板迭代器我们传参不一样,决定了是const还是普通
typedef _list_iterator<T, T&, T*> iterator;
typedef _list_iterator<T,const T&,const T*> const_iterator;iterator begin(){//return iterator(_head->data);return _head->_next;}iterator end(){return _head;//哨兵位就是链表的结束标志}const_iterator begin()const{return _head->_next;}const_iterator end()const{return _head;}
成员函数
构造函数
//通过调用一个初始化链表的函数来实现构造函数mylist(){empty_init();}
析构函数
//通过调用clear函数释放链表的节点,在释放哨兵位,即为析构~mylist(){clear();delete _head;_head = nullptr;}
拷贝构造函数
//拷贝构造,将节点尾插入新的对象mylist(mylist<T>& p){empty_init(p);for (auto it : p){push_back(it);}}
容量
size
size_t size(){return _size;}
修饰符
insert()
在基于实现insert,我们的其他对list的操作都可以调用insert,不需要都去对链表节点一个个操作,
其次我们设计insert的返回值及参数位置都是迭代器,直接用。
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);}
erase ()
//删除 这里删除cur节点释放掉,会导致迭代器失效,因此要返回下一节点的迭代器iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;prev->_next = next;next->_prev = prev;_size--;return iterator(next);}
push_front()
void push_front(){insert(begin());}
pop_front()
//头删void pop_front(){erase(begin());}
push_back()
//尾插void push_back(const T& x){//Node* tail = _head->preav;//Node* newnode = new Node(x);连接节点//tail->_next = newnode;//newnode->_next = _head;//newnode->prev = tail;//tail->_prev = newnode;//tail = newnode;//return (tail);insert(end(), x);}
pop_back()
//尾删void pop_back(){erase(end());}
clear()
//清数据void clear(){iterator it = begin();while (it != end()){it = erase(it);}}
至此我们对list的简单实现就完成了。
相关文章:
C++学习之list的实现
在了解学习list实现之前我们首先了解一下关于迭代器的分类: 按功能分类: 正向迭代器 反向迭代器 const正向迭代器 const反向迭代器 按性质分类: 单向迭代器 只能 例如单链表 双向迭代器 可,也可-- 例如双…...
一种高效且节约内存的聚合数据结构的实现
一种高效且节约内存的聚合数据结构的实现 在特定的场景中,特殊定制数据结构能够得到更加好的性能且更节约内存。 聚合函数GroupArray的问题 GroupArray聚合函数是将分组内容组成一个个数组,例如下面的例子: SELECT groupArray(concat(ABC…...
机器学习(10)---特征选择
文章目录 一、概述二、Filter过滤法2.1 过滤法说明2.2 方差过滤2.3 方差过滤对模型影响 三、相关性过滤3.1 卡方过滤3.2 F检验3.3 互信息法3.4 过滤法总结 四、Embedded嵌入法4.1 嵌入法说明4.2 以随机森林为例的嵌入法 五、Wrapper包装法5.1 包装法说明5.2 以随机森林为例的包…...
Python之数据库(MYSQL)连接
一)数据库SQL语言基础 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database…...
【建站教程】使用阿里云服务器怎么搭建网站?
使用阿里云服务器快速搭建网站教程,先为云服务器安装宝塔面板,然后在宝塔面板上新建站点,阿里云服务器网以搭建WordPress网站博客为例,阿小云来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流程&#x…...
【自然语言处理】关系抽取 —— MPDD 讲解
MPDD 论文信息 标题:MPDD: A Multi-Party Dialogue Dataset for Analysis of Emotions and Interpersonal Relationships 作者:Yi-Ting Chen, Hen-Hsen Huang, Hsin-Hsi Chen 期刊:LREC 2020 发布时间与更新时间:2020 主题:自然语言处理、关系抽取、对话场景、情感预测 数…...
深入理解JVM虚拟机第三篇:JVM的指令集架构模型和JVM的生命周期
文章目录 一:JVM的指令集架构模型 1:基于栈式架构的特点...
[小尾巴 UI 组件库] 组件库配置与使用
文章归档于:https://www.yuque.com/u27599042/row3c6 组件库地址 npm:https://www.npmjs.com/package/xwb-ui?activeTabreadme小尾巴 UI 组件库源码 gitee:https://gitee.com/tongchaowei/xwb-ui小尾巴 UI 组件库测试代码 gitee:…...
Linux系统中fork()函数的理解
fork() 函数是一个在Unix和类Unix操作系统中常见的系统调用,用于创建一个新的进程,该进程是调用进程(父进程)的副本。fork() 函数的工作原理如下: 1. 当父进程调用 fork() 时,操作系统会创建一个新的进程&a…...
Linux网络编程:网络协议及网络传输的基本流程
目录 一. 计算机网络的发展 二. 网络协议的认识 2.1 对于协议分层的理解 2.2 TCP/IP五层协议模型 2.3 OSI七层模型 三. 网络传输的流程 3.1 同一网段中计算机通信的流程 3.2 不同网段中计算机设备的通信 3.3 对于IP地址和MAC地址的理解 3.4 数据的封装和解包 四. 总结…...
【大数据之Kafka】十、Kafka消费者工作流程
1 Kafka消费方式 (1)pull(拉)模式:消费者从broker中主动拉取数据。(Kafka中使用) 不足:如果Kafka中没有数据,消费者可能会陷入循环,一直返回空数据。 &#…...
如何确保ChatGPT的文本生成对特定行业术语的正确使用?
确保ChatGPT在特定行业术语的正确使用是一个重要而复杂的任务。这涉及到许多方面,包括数据预处理、模型训练、微调、评估和监控。下面我将详细介绍如何确保ChatGPT的文本生成对特定行业术语的正确使用,并探讨这一过程中的关键考虑因素。 ### 1. 数据预处…...
行业追踪,2023-09-11
自动复盘 2023-09-11 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…...
LVS + Keepalived群集
文章目录 1. Keepalived工具概述1.1 什么是Keepalived1.2 工作原理1.3 Keepailved实现原理1.4 Keepalived体系主要模块及其作用1.5 keepalived的抢占与非抢占模式 2. 脑裂现象 (拓展)2.1 什么是脑裂2.2 脑裂的产生原因2.3 如何解决脑裂2.4 如何预防脑裂 …...
springboot将jar改成war
一、maven项目 1、修改pom文件 <packaging>war</packaging>2、添加Servlet API依赖,Spring Boot的Starter依赖通常会包含这个依赖,所以你可能已经有了,没有就需要添加 <dependency><groupId>javax.servlet</gr…...
从9.10拼多多笔试第四题产生的01背包感悟
文章目录 题面基本的01背包问题本题变式 本文参考: 9.10拼多多笔试ak_牛客网 (nowcoder.com) 拼多多 秋招 2023.09.10 编程题目与题解 (xiaohongshu.com) 题面 拼多多9.10笔试的最后一题,是一道比较好的01背包变式问题,可以学习其解法加深对…...
搭建自己的OCR服务,第一步:选择合适的开源OCR项目
一、OCR是什么? 光学字符识别(Optical Character Recognition, OCR)是指对文本资料的图像文件进行分析识别处理,获取文字及版面信息的过程。 亦即将图像中的文字进行识别,并以文本的形式返回。 二、OCR的基本流程 1…...
【C++】VScode配置C/C++语言环境(简洁易懂版)
目录 一、下载VScode(装好直接跳第五步)二、安装VScode三、VScode设置语言为中文四、VScode切换主题(个人爱好)五、下载C语言编译器(MinGW-W64 GCC)六、配置编译器环境变量七、配置VScode八、使用单独窗口…...
【hive】—原有分区表新增加列(alter table xxx add columns (xxx string) cascade;)
项目场景: 需求:需要在之前上线的分区报表中新增加一列。 实现方案: 1、创建分区测试表并插入测试数据 drop table test_1; create table test_1 (id string, score int, name string ) partitioned by (class string) row format delimit…...
verilog学习笔记7——PMOS和NMOS、TTL电路和CMOS电路
文章目录 前言一、PMOS和NMOS1、NMOS2、PMOS3、增强型和耗尽型4、两者面积大小 二、CMOS门电路1、非门2、与非门3、或非门4、线与逻辑5、CMOS传输门6、三态门 三、TTL电路四、TTL电路 VS CMOS电路五、数字电平六、使用CMOS电路实现逻辑函数1、上拉网络 PUN2、下拉网络 PDN3、实…...
Linux系统下Filezilla FTP客户端的两种高效部署方案
1. 为什么选择Filezilla作为Linux平台的FTP客户端? 作为Linux用户,我们经常需要在服务器之间传输文件。虽然命令行工具如scp、sftp也能完成工作,但图形化客户端在批量文件操作和可视化管理方面优势明显。Filezilla作为老牌开源FTP解决方案&am…...
深入浅出:用Grad-CAM解锁Swin Transformer的视觉注意力
1. 为什么需要理解Swin Transformer的视觉注意力? 当你第一次看到Swin Transformer在图像分类任务中表现出色时,可能会好奇它到底"看"到了图像的哪些部分。传统的卷积神经网络(CNN)通过局部感受野逐步提取特征ÿ…...
光耦LED寿命评估与可靠性设计实践
1. 光耦LED寿命评估的核心价值 在工业自动化控制系统中,我曾亲眼目睹一个价值数百万的生产线因为光耦器件失效导致整个控制系统误动作。故障排查时发现,正是光耦内部的LED光源经过5年连续工作后出现严重光衰,使得信号传输出现错误。这个教训让…...
AgentKernel:构建模块化智能体系统的核心引擎设计
1. 项目概述:从“AgentKernel”看智能体开发范式的演进最近在GitHub上看到一个名为“AgentKernel”的项目,作者是vijaygopalbalasa。这个标题本身就很有意思,它没有直接叫“AgentFramework”或者“AgentPlatform”,而是选择了“Ke…...
AI短视频生成引擎:从文章到视频的自动化流水线实战
1. 项目概述:一个能“读懂”文章的AI视频工厂最近在折腾短视频内容创作的朋友,估计都经历过一个共同的痛点:找选题、写脚本、找素材、配音、剪辑……一套流程下来,几个小时就没了,效率低得让人抓狂。尤其是想把一篇深度…...
别再死记硬背了!用PyTorch和TensorFlow动手实现池化层,5分钟搞懂Max Pooling和Average Pooling的区别
用PyTorch和TensorFlow实战池化层:5分钟可视化Max与Average Pooling差异 刚接触深度学习的开发者常被各种理论概念困扰,尤其是池化层这类看似简单却暗藏玄机的操作。与其死记硬背定义,不如打开Jupyter Notebook,用PyTorch和Tensor…...
Xilinx 7系列FPGA目标设计平台:从芯片到生态的系统开发革命
1. 项目概述:Xilinx 7系列FPGA设计平台的划时代意义作为一名在数字系统设计领域摸爬滚打了十几年的工程师,我至今还记得2012年初听到Xilinx发布其28nm 7系列FPGA首批“目标设计平台”时的兴奋感。那感觉就像是,一直需要自己从零开始搭积木、焊…...
从AgentKit看AI应用工程化:架构演进与可靠性设计
1. 项目概述:一个已归档的AI应用快速启动器如果你在2023年到2024年初关注过AI应用开发,特别是基于大语言模型(LLM)的智能体(Agent)构建,那么你很可能听说过或者尝试过AgentKit。这个由BCG X&…...
告别DETR训练慢!用Deformable DETR在COCO数据集上快速搞定小目标检测(附PyTorch代码)
告别DETR训练慢!用Deformable DETR在COCO数据集上快速搞定小目标检测(附PyTorch代码) 在目标检测领域,DETR(Detection Transformer)以其端到端的特性吸引了大量关注,但实际应用中暴露出两个致命…...
如何快速清理电脑中的重复图片:AntiDupl.NET终极指南
如何快速清理电脑中的重复图片:AntiDupl.NET终极指南 【免费下载链接】AntiDupl A program to search similar and defect pictures on the disk 项目地址: https://gitcode.com/gh_mirrors/an/AntiDupl 你是否曾因电脑中堆积如山的重复图片而烦恼࿱…...
