C++初阶:适合新手的手撕list(模拟实现list)

上次讲了常用的接口:今天就来进行模拟实现啦


文章目录

  • 1.基本结构与文件规划
  • 2.空参构造函数(constructor)
  • 3.完善迭代器(iterator)(begin(),end())
  • 4.List Capacity(size(),empty())
  • 4.增删改查(push_back,pop_back,pop_front,push_front,insert,erase)
  • 6.clear()和swap()
  • 7. 完善构造函数
    • 7.1list (size_type n, const value_type& val = value_type());
    • 7.2利用迭代器进行构造
    • 7.3拷贝构造
  • 8.重载=
  • 9.析构函数
  • 10.反向迭代器


1.基本结构与文件规划

请添加图片描述

  • list.h头文件:包含类的全部(函数的声明与定义)
  • reverseIterator.h文件:进行反向迭代器的实现
  • test.cpp源文件:进行调用test函数,测试和完善功能

基本结构:

#pragma oncenamespace MyList
{// List的节点类template<class T>struct ListNode{ListNode<T>* _prev;ListNode<T>* _next;T _data;ListNode(const T& x=T()):_prev(nullptr),_next(nullptr),_data(x){}};//List的迭代器类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){}ListIterator(const Self& l)//拷贝构造函数:_node(l._node){}T& operator*();T* operator->();Self& operator++();Self operator++(int);Self& operator--();Self& operator--(int);bool operator!=(const Self& l);bool operator==(const Self& l);};//list类template<class T>class list{typedef ListNode<T> Node;//默认是private 不给外面用public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;//构造函数list();list(int n, const T& value = T());template <class Iterator>list(Iterator first, Iterator last);//析构~list();// List Iteratoriterator begin();iterator end();const_iterator begin();const_iterator end();// List Capacitysize_t size()const;bool empty()const;// List AccessT& front();const T& front()const;T& back();const T& back()const;// List Modifyvoid push_back(const T& val) { insert(end(), val); }void pop_back() { erase(--end()); }void push_front(const T& val) { insert(begin(), val); }void pop_front() { erase(begin()); }// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val);// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos);void clear();void swap(list<T>& l);private:Node* _head;};
};
  1. ListNode 结构体:
    • 定义了链表的节点结构,包含了三个成员变量:前驱指针 _prev、后继指针 _next 和数据 _data
    • 构造函数初始化了这些成员变量,允许在创建节点时指定初始值。
  2. ListIterator 结构体:
    • 定义了链表的迭代器结构,包含了指向节点的指针 _node
    • 重载了一系列操作符,如 *->++--!===,以便于对链表进行遍历和操作。
  3. list 类:
    • 包含了迭代器的定义、构造函数、析构函数以及一系列的操作函数。
    • 定义了两种迭代器类型:iteratorconst_iterator,分别用于可修改的迭代和只读的迭代。
    • 实现了一系列的操作函数

2.空参构造函数(constructor)

        list(){_head = new Node;//去调用Node的默认构造函数了_head->_next = _head;_head->_prev = _head;//带头双向循环链表是这样的}

使用new:动态开辟+调用默认构造函数了


3.完善迭代器(iterator)(begin(),end())

这里为什么我们要把迭代器封装为一个类呢?明明之前模拟vectorstring时,就直接typedef

之前模拟vectorstring时,二者底层都是连续的,想要到下一个可以直接++;想要得到里面的数据可以直接*

但是现在对于list是不行的,我们就需要重载各种运算符,但是底层又是一个指针(内置类型)不能重载,现在就只能封装进一个类里,就能重载

 //List的迭代器类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){}ListIterator(const Self& l)//拷贝构造函数:_node(l._node)//这里是浅拷贝(写不写都行)//新创建的迭代器和原迭代器指向相同的内存地址{}Ref operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data);}Self& operator++()//前置{_node = _node->_next;//自己要更新return *this;}Self operator++(int){Self s(*this);_node = _node->_next;return s;}Self& operator--(){_node = _node->_prev;//自己要更新return *this;}Self& operator--(int){Self s(*this);_node = _node->_prev;return s;}bool operator!=(const Self& l){return _node != l._node;}bool operator==(const Self& l){return _node == l._node;}};//list类template<class T>class list{typedef ListNode<T> Node;//默认是private 不给外面用public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;//构造函数list(){_head = new Node;//去调用Node的默认构造函数了_head->_next = _head;_head->_prev = _head;//带头双向循环链表是这样的}// List Iteratoriterator begin(){return _head->_next;//隐式类型转换(由单参构造函数支撑)}iterator end(){return _head;}const_iterator begin(){return _head->_next;}const_iterator end(){return _head;}private:Node* _head;};
};

4.List Capacity(size(),empty())

       // List Capacitysize_t size()const{size_t size = 0;iterator it = begin();while (it != end()){size++;++it;}return size;}bool empty()const{return size() == 0;}

4.增删改查(push_back,pop_back,pop_front,push_front,insert,erase)

        // List Modifyvoid push_back(const T& val) //尾插{ insert(end(), val); }void pop_back() //尾删{ erase(--end());}void push_front(const T& val) //头插{ insert(begin(), val);}void pop_front()//头删{ erase(begin());}// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* cur = pos._node;Node* prev = pos._node->_prev;Node* newnode = new Node(val);//创建新节点newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;prev->_next = cur;return newnode;//隐式类型转换}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(pos != _head);Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;return next;}

使用test1函数看功能是否正常

	void print(MyList::list<int>& lt){list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << " ";++it; // 更新迭代器}cout << endl;}void test1(){MyList::list<int> lt;lt.push_back(1);lt.push_back(2);//尾插2个print(lt);lt.pop_back();//尾删一个print(lt);lt.push_front(0);//头插一个print(lt);lt.pop_front();//头删一个print(lt);}

请添加图片描述


6.clear()和swap()

       void clear(){//删除除头结点(_head)以外的节点iterator it = begin();while (it != end()){it = erase(it);}}void swap(list<T>& l){std::swap(_head, l._head);}

7. 完善构造函数

7.1list (size_type n, const value_type& val = value_type());

list(int n, const T& value = T())
{_head = new Node;_head->_next = _head;_head->_prev = _head;for (int i = 0; i < n; ++i){push_back(value);}
}

请添加图片描述

7.2利用迭代器进行构造

	    template <class Iterator>list(Iterator first, Iterator last){while (first != last){push_back(*first);first++;}}

为什么使用模版:

因为可能使用其他类型的迭代器来进行初始化

7.3拷贝构造

        list(const list<T>& lt){_head = new Node;_head->_next = _head;_head->_prev = _head;iterator it = copy.begin();while (it != copy.end()){push_back(*it);it++;}}

8.重载=

        list<T>& lt operator=(list<T> lt){swap(lt);return *this;}

注意这里的参数不是常量引用,而是按值传递的。这是因为在赋值操作符中我们会调用 swap 函数,按值传递可以保证传入的参数会被复制一份,避免对原对象的修改。在函数体内,我们调用了 swap 函数,将当前对象和传入的对象进行内容交换,然后返回 *this,即当前对象的引用。


9.析构函数

        ~list(){clear();delete _head;_head = nullptr;}

调用clear函数后,就只剩下头结点了


10.反向迭代器

我们再次使用封装的思想,封装一个反向迭代器进去

#pragma oncetemplate <class iterator,class Ref,class Pre>
struct reserve_iterator
{typedef reserve_iterator<iterator, Ref, Pre> self;iterator _it;reserve_iterator(iterator it):_it(it)  {}self& operator++(){--_it;return *this;}self operator++(int){self tmp = *this;--_it;return tmp;}self& operator--(){++_it;return *this;}self operator--(int){self tmp = *this;++_it;return tmp;}Ref operator*(){iterator tmp = _it;--tmp;return *tmp;}Pre operator->(){return &(operator*());}bool operator!=(const self& s){return _it != s._it;}bool operator==(const self& s){return _it == s._it;}};

此时那list类里就是这样:

请添加图片描述


好啦,list的内容也结束啦,下次就是Stack和Queue了。感谢大家支持!!!

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

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

相关文章

C++ bfs反向搜索(五十七)【第四篇】

今天我们来学习bfs的反向搜索。 1.反向搜索 反向搜索&#xff1a;是从目标状态出发进行的搜索&#xff0c;一般用于终点状态唯一&#xff0c;起点状态有多种&#xff0c;且状态转移是可逆的&#xff08;无向边&#xff09;情况。 例题&#xff1a;在一个长度为 n 的坐标轴上&a…

2024年【T电梯修理】报名考试及T电梯修理复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 T电梯修理报名考试参考答案及T电梯修理考试试题解析是安全生产模拟考试一点通题库老师及T电梯修理操作证已考过的学员汇总&#xff0c;相对有效帮助T电梯修理复审考试学员顺利通过考试。 1、【多选题】增加旧电梯曳引…

p图考试,搜题软件哪个好?如何利用大学搜题工具查找特定学科的题目? #微信#知识分享

大学生必备&#xff0c;这条笔记大数据一定定要推给刚上大学的学弟学妹&#xff01;&#xff01; 1.三羊搜题 这是个微信公众号 是个公众号&#xff0c;支持文字、语音、截图搜题&#xff0c;截图搜题&#xff0c;同时也支持相似题查看及解析&#xff0c;因为可以在电脑上使…

【医学图像分割 2024】VM-UNet

文章目录 【医学图像分割 2024】VM-UNet摘要1. 介绍2. 预备知识3. 方法3.1 VM-UNet3.2 VSS Block3.3 损失函数 4. 实验4.1 数据集4.2 实现细节4.3 主要结果4.4 消融实验 5. 结果 【医学图像分割 2024】VM-UNet 论文题目&#xff1a;VM-UNet Vision Mamba UNet for Medical Imag…

Junit测试套件(Test Suite)

0. 什么是测试套件 对多个测试类的统一执行 只有一个测试类 点击一下执行就好有 5个测试类 分别打开 挨个点执行有100个测试类 &#xff1f;&#xff1f;分别点开执行 为100个测试类创建一个测试套件&#xff0c;然后再执行一次测试套件 √ 一个测试套件“囊括“三个测试类…

[嵌入式系统-16]:RT-Thread -2- 主要功能功能组件详解与API函数说明

目录 一、RT-Thread主要功能组件 二、内核组件 2.1 概述 2.2 API 三、设备驱动 3.1 概述 3.2 API 四、通信组件 4.1 概述 4.4 API 五、网络组件 5.1 概述 5.2 API 5.3 补充&#xff1a;MQTT协议 六、文件系统 6.1 概述 6.2 API 七、GUI 组件 7.1 概述 7.2 …

[office] Excel CHITEST 函数 使用实例教程 #媒体#知识分享#其他

Excel CHITEST 函数 使用实例教程 提示 此函数已由 CHISQ.TEST 函数替换&#xff0c;新函数可以提供更好的精确度&#xff0c;其名称更好地反映其用法。旧函数仍可用于与早期版本Excel 的兼容。但是&#xff0c;如果不需要向后兼容&#xff0c;那么应考虑直接使用新函数&…

【AIGC】Stable Diffusion的模型微调

为什么要做模型微调 模型微调可以在现有模型的基础上&#xff0c;让AI懂得如何更精确生成/生成特定的风格、概念、角色、姿势、对象。Stable Diffusion 模型的微调方法通常依赖于您要微调的具体任务和数据。 下面是一个通用的微调过程的概述&#xff1a; 准备数据集&#xf…

平时积累的FPGA知识点(6)

平时在FPGA群聊等积累的FPGA知识点&#xff0c;第六期&#xff1a; 1 万兆网接口&#xff0c;发三十万包&#xff0c;会出现掉几包的情况&#xff0c;为什么&#xff1f; 原因&#xff1a;没做时钟约束&#xff0c;万兆网接口的实现&#xff0c;本质上都是高速serdes&#xf…

MinGW下载安装教程 傻瓜式操作【超详细】

一、下载 下载地址&#xff1a;MinGW - Minimalist GNU for Windows - Browse Files at SourceForge.net 点击“Download Latest Version”即可 注意&#xff1a;小伙伴儿们也可以私信我要安装包。 二、安装 下载完成后&#xff0c;会得到一个名为 mingw-get-setup.exe 的安…

机器学习网格搜索超参数优化实战(随机森林) ##4

文章目录 基于Kaggle电信用户流失案例数据&#xff08;可在官网进行下载&#xff09;数据预处理模块时序特征衍生第一轮网格搜索第二轮搜索第三轮搜索第四轮搜索第五轮搜索 基于Kaggle电信用户流失案例数据&#xff08;可在官网进行下载&#xff09; 导入库 # 基础数据科学运…

系统架构27 - 软件架构设计(6)

基于架构的软件开发方法 基于架构的软件开发方法&#xff08;ABSD&#xff09;概述概念与术语开发模型体系结构需求体系结构设计体系结构文档化体系结构复审体系结构实现体系结构的演化 基于架构的软件开发方法&#xff08;ABSD&#xff09; 基于体系结构的软件设计 (Architec…

【JavaEE】_文件与IO

目录 1.文件概述 1.1 文件的概念 1.2 文件的存储 1.3 文件的分类 1.4 目录结构 1.5 文件操作 1.5.1 文件系统操作 1.5.2 文件内容操作 2. Java文件系统操作 2.1 File类所处的包 2.2 构造方法 2.3 方法 2.3.1 与文件路径、文件名有关的方法 2.3.2 文件是否存在与普…

openGauss学习笔记-221 openGauss性能调优-确定性能调优范围-分析作业是否被阻塞

文章目录 openGauss学习笔记-221 openGauss性能调优-确定性能调优范围-分析作业是否被阻塞221.1 操作步骤 openGauss学习笔记-221 openGauss性能调优-确定性能调优范围-分析作业是否被阻塞 数据库系统运行时&#xff0c;在某些业务场景下查询语句会被阻塞&#xff0c;导致语句…

【MySQL】操作库 —— 表的操作 -- 详解

一、增加表 1、创建表 mysql> create database [if not exists] table_name ( -> field1 datatype, -> field2 datatype, -> field3 datatype -> ) character set 字符集 collate 校验规则 engine 存储引擎; 注意 &#xff1a;最后一行也可以写成&#x…

Vue源码系列讲解——模板编译篇【二】(整体运行流程)

目录 1. 整体流程 2. 回到源码 3. 总结 1. 整体流程 上篇文章中我们说了&#xff0c;在模板解析阶段主要做的工作是把用户在<template></template>标签内写的模板使用正则等方式解析成抽象语法树&#xff08;AST&#xff09;。而这一阶段在源码中对应解析器&…

c语言操作符(上)

目录 ​编辑 原码、反码、补码 1、正数 2、负数 3、二进制计算1-1 移位操作符 1、<<左移操作符 2、>>右移操作符 位操作符&、|、^、~ 1、&按位与 2、|按位或 3、^按位异或 特点 4、~按位取反 原码、反码、补码 1、正数 原码 反码 补码相同…

STM32 HAL库 STM32CubeMX -- IWDG(独立看门狗)

STM32 HAL库 STM32CubeMX -- IWDG 一、IWDG简介二、独立看门狗的工作原理三、驱动函数初始化函数HAL IWDG Init()初始化函数HAL IWDG Init()其他宏函数 四、超时时间计算第一种办法第二种办法&#xff08;推荐&#xff09; 一、IWDG简介 看门狗(Watchdog)就是MCU上的一种特殊的…

【AIGC】Stable Diffusion的模型入门

下载好相关模型文件后&#xff0c;直接放入Stable Diffusion相关目录即可使用&#xff0c;Stable Diffusion 模型就是我们日常所说的大模型&#xff0c;下载后放入**\webui\models\Stable-diffusion**目录&#xff0c;界面上就会展示相应的模型选项&#xff0c;如下图所示。作者…

计算机网络——多媒体网络

前些天发现了一个巨牛的人工智能学习网站 通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff0c; 跳转到网站 小程一言 我的计算机网络专栏&#xff0c;是自己在计算机网络学习过程中的学习笔记与心得&#xff0c;在参考相关教材&#xff0c;网络搜素…