当前位置: 首页 > news >正文

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了。感谢大家支持!!!

相关文章:

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

上次讲了常用的接口&#xff1a;今天就来进行模拟实现啦 文章目录 1.基本结构与文件规划2.空参构造函数&#xff08;constructor)3.完善迭代器&#xff08;iterator&#xff09;(begin(),end())4.List Capacity&#xff08;size(),empty())4.增删改查(push_back,pop_back,pop_f…...

js手写Promise(上)

目录 构造函数resolve与reject状态改变状态改变后就无法再次改变 代码优化回调函数中抛出错误 thenonFulfilled和onRejected的调用时机异步then多个then 如果是不知道或者对Promise不熟悉的铁铁可以先看我这篇文章 Promise 构造函数 在最开始&#xff0c;我们先不去考虑Promi…...

基于Web技术的家居室内温湿度监测系统

设计一个基于Web技术的家居室内温湿度监测系统涉及前端和后端开发&#xff0c;以及与硬件传感器的集成。以下是一个简单的设计概述&#xff1a; ### 1. 系统架构 - **前端**: 用户界面&#xff0c;用于显示实时数据和历史记录&#xff0c;可通过Web浏览器访问。 - **后端**: 服…...

ubuntu22.04@laptop OpenCV Get Started: 009_image_thresholding

ubuntu22.04laptop OpenCV Get Started: 009_image_thresholding 1. 源由2. image_thresholding应用Demo2.1 C应用Demo2.2 Python应用Demo 3. 重点分析3.1 Binary Thresholding ( THRESH_BINARY )3.2 Inverse-Binary Thresholding ( THRESH_BINARY_INV )3.3 Truncate Threshold…...

Zeek实战—快速构建流量安全能力

第1章 网络流量与网络安全 1.2流量与网络 从宏观角度进行观察&#xff0c;如果将计算机网络看作一个整体&#xff0c;可以很容易抽象出它是由以下3个部分组成的。 1.网络终端。指连接在网络中的、能够产生或消费网络流量的软/硬件系统&#xff0c;是网络流量在正常情况下的…...

vim命令编辑完文件后,按ESC键退出编辑模式,无法进入命令模式解决方案

发现问题 在Vim编辑器中&#xff0c;我们通常需要按Esc键来退出编辑模式并进入命令模式。但有时&#xff0c;你可能会发现即使按了Esc键&#xff0c;也无法进入命令模式。这可能是由于某些设置或插件导致的。不过&#xff0c;有一个解决办法可以帮助你解决这个问题。 解决办法…...

【生产实测有效】Linux磁盘清理常用命令

经常遇到磁盘空间告警需要清理 常用方法 磁盘空间分析 先查看整体磁盘空间使用情况 df -Th lsblk 再有针对性的查看使用率过高的磁盘 du -hsx --exclude/{proc,sys,dev,boot,home,tmp,usr,var,app,ncltybbpo} /*查找大文件 find . -type d -exec tar -cjvf {}.tar.bz2 {…...

练习:鼠标类设计之1_类内容解析

前言 光做理论上的总结,不做练习理解不会那么深刻 做类的练习,解析类里面的内容有哪些 引入 电脑使用最频繁的两个外设:鼠标和键盘,他们每时每刻都在和用户交互,试做一个鼠标类 思路 我们现在要做一个鼠标类,这个类是属于能动类还是资源类呢?鼠标似乎自己做不了什么,需要和其…...

消息队列RabbitMQ-使用过程中面临的问题与解决思路

消息队列在使用过程中会出现很多问题 首先就是消息的可靠性&#xff0c;也就是消息从发送到消费者接收&#xff0c;消息在这中间过程中可能会丢失 生产者到交换机的过程、交换机到队列的过程、消息队列中、消费者接收消息的过程中&#xff0c;这些过程中消息都可能会丢失。 …...

搜索Agent方案

为啥需要整体方案&#xff0c;直接调用搜索接口取Top1返回不成嘛&#xff1f;要是果真如此Simple&Naive&#xff0c;New Bing岂不是很容易复刻->.-> 我们先来看个例子&#xff0c;前一阵火爆全网的常温超导技术&#xff0c;如果想回答LK99哪些板块会涨&#xff0c;你…...

排序算法---计数排序

原创不易&#xff0c;转载请注明出处。欢迎点赞收藏~ 计数排序&#xff08;Counting Sort&#xff09;是一种线性时间复杂度的排序算法&#xff0c;其核心思想是通过统计待排序元素的个数来确定元素的相对位置&#xff0c;从而实现排序。 具体的计数排序算法步骤如下&#xff…...

STM32——LCD(1)认识

目录 一、初识LCD 1. LCD介绍 2. 显示器的分类 3. 像素 4. LED和OLED显示器 5. 显示器的基本参数 &#xff08;1&#xff09;像素 &#xff08;2&#xff09;分辨率 &#xff08;3&#xff09;色彩深度 &#xff08;4&#xff09;显示器尺寸 &#xff08;5&#xff…...

iTop-4412 裸机程序(二十二)- RTC时钟

目录 0.源码1. RTC2. iTop4412 中的 RTC使用的相关寄存器3. BCD编码4. 关键源码 0.源码 GitHub&#xff1a;https://github.com/Kilento/4412NoOS 1. RTC RTC是实时时钟&#xff08;Real Time Clock&#xff09;的缩写&#xff0c;是一种用于计算机系统的硬件设备&#xff0…...

Kafka 之 AdminClient API

目录 一. 前言 二. KafkaAdminClient API 2.1. API 总览 2.2. Topic 操作 2.2.1. 创建 Topic 2.2.2. Topic 列表 2.2.3. 删除 Topic 2.2.4. 描述 Topic 详细信息 2.3. 分区 Partition 操作 2.3.1. 增加分区 2.3.2. 分区副本重新分配 2.3.3. 查询分区副本列表 2.4.…...

Flutter run 一直 Running Gradle task ‘assembleDebug’…

发生缘由 Flutter 项目引入 fluttertoast 插件后&#xff0c;执行 Flutter run 一直 Running Gradle task ‘assembleDebug’…&#xff0c;最后发现下载 kotlin-compiler-embeddable-7.1.0.jar 特别的缓慢。 运行环境 电脑系统版本&#xff1a;Windows 10 64bit VS Code&…...

kali无线渗透之用wps加密模式破解出wpa模式的密码12

WPS(Wi-Fi Protected Setup&#xff0c;Wi-Fi保护设置)是由Wi-Fi联盟推出的全新Wi-Fi安全防护设定标准。该标准推出的主要原因是为了解决长久以来无线网络加密认证设定的步骤过于繁杂之弊病&#xff0c;使用者往往会因为步骤太过麻烦&#xff0c;以致干脆不做任何加密安全设定&…...

【Python】高级数据类型

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…...

挑战杯 python区块链实现 - proof of work工作量证明共识算法

文章目录 0 前言1 区块链基础1.1 比特币内部结构1.2 实现的区块链数据结构1.3 注意点1.4 区块链的核心-工作量证明算法1.4.1 拜占庭将军问题1.4.2 解决办法1.4.3 代码实现 2 快速实现一个区块链2.1 什么是区块链2.2 一个完整的快包含什么2.3 什么是挖矿2.4 工作量证明算法&…...

如何给最小化安装的CentOS主机装个远程桌面?

正文共&#xff1a;888 字 18 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面我们领微软云Azure的免费主机时&#xff08;白嫖党618福利&#xff01;来Azure领200美刀&#xff01;外加云主机免费用一年&#xff01;&#xff09;&#xff0c;发现“有资格免费试用服务”的主…...

知识图谱:py2neo将csv文件导入neo4j

文章目录 安装py2neo创建节点-连线关系图导入csv文件删除重复节点并连接边 安装py2neo 安装python中的neo4j操作库&#xff1a;pip install py2neo 安装py2neo后我们可以使用其中的函数对neo4j进行操作。 图数据库Neo4j中最重要的就是结点和边&#xff08;关系&#xff09;&a…...

解决Mac视频预览难题:QuickLookVideo工具的创新方案

解决Mac视频预览难题&#xff1a;QuickLookVideo工具的创新方案 【免费下载链接】QuickLookVideo This package allows macOS Finder to display thumbnails, static QuickLook previews, cover art and metadata for most types of video files. 项目地址: https://gitcode.…...

Colmap避坑指南:如何用SuperPoint+SuperGlue提升三维重建精度(附错误案例修复)

Colmap三维重建精度提升实战&#xff1a;从特征匹配优化到工业级解决方案 在计算机视觉领域&#xff0c;三维重建技术已经从实验室走向工业应用&#xff0c;而Colmap作为开源摄影测量工具链的核心&#xff0c;其重建精度直接决定了后续NeRF或Gaussian Splatting等神经渲染技术的…...

3秒守护隐私:Boss-Key重新定义窗口智能管理

3秒守护隐私&#xff1a;Boss-Key重新定义窗口智能管理 【免费下载链接】Boss-Key 老板来了&#xff1f;快用Boss-Key老板键一键隐藏静音当前窗口&#xff01;上班摸鱼必备神器 项目地址: https://gitcode.com/gh_mirrors/bo/Boss-Key 在数字化办公环境中&#xff0c;窗…...

告别VS Code后,我在Trae里这样调教Dracula主题和代码片段(附同步指南)

从VS Code到Trae&#xff1a;打造极致Dracula主题与高效代码片段的完整指南 第一次在Trae里看到默认的白色主题时&#xff0c;我的眼睛几乎被闪瞎——这感觉就像半夜突然被强光手电筒直射瞳孔。作为从VS Code"叛逃"过来的开发者&#xff0c;我花了整整两周时间把Trae…...

OpenClaw+GLM-4.7-Flash:个人旅行计划自动生成与优化

OpenClawGLM-4.7-Flash&#xff1a;个人旅行计划自动生成与优化 1. 为什么需要AI旅行助手&#xff1f; 去年夏天&#xff0c;我计划带家人去云南旅行时&#xff0c;花了整整三个晚上对比机票价格、筛选酒店、计算景点间的交通时间。当我在凌晨两点盯着Excel表格里混乱的日期和…...

驱动级输入模拟技术:突破Windows系统限制的Interceptor解决方案

驱动级输入模拟技术&#xff1a;突破Windows系统限制的Interceptor解决方案 【免费下载链接】Interceptor C# wrapper for a Windows keyboard driver. Can simulate keystrokes and mouse clicks in protected areas like the Windows logon screen (and yes, even in games).…...

AI超清画质增强镜像使用技巧:避免移动端适配的3个坑

AI超清画质增强镜像使用技巧&#xff1a;避免移动端适配的3个坑 1. 理解镜像的核心能力与限制 在移动端使用AI超清画质增强镜像前&#xff0c;必须清楚了解它能做什么、不能做什么。这个基于OpenCV EDSR模型的镜像&#xff0c;本质上是一个专注图像重建的轻量级服务。 1.1 核…...

CCF-GESP C++三级备考避坑指南:从2023年12月真题看数组、字符串的5个易错点

CCF-GESP C三级备考避坑指南&#xff1a;从2023年12月真题看数组、字符串的5个易错点 对于准备参加CCF-GESP C三级考试的学生来说&#xff0c;掌握数组和字符串的使用是基础中的基础。然而&#xff0c;正是这些看似简单的知识点&#xff0c;往往成为考试中的"隐形杀手&quo…...

Navicat密码解密工具:企业级数据安全与密码恢复解决方案

Navicat密码解密工具&#xff1a;企业级数据安全与密码恢复解决方案 【免费下载链接】navicat_password_decrypt 忘记navicat密码时,此工具可以帮您查看密码 项目地址: https://gitcode.com/gh_mirrors/na/navicat_password_decrypt Navicat密码解密工具是一款专为数据库…...

零配置部署!VoxCPM-1.5-WEBUI让语音合成变得像上网一样简单

零配置部署&#xff01;VoxCPM-1.5-WEBUI让语音合成变得像上网一样简单 你是否曾为视频配音找不到合适的声音而烦恼&#xff1f;是否想过制作有声读物却苦于录音设备和时间成本&#xff1f;或者&#xff0c;你只是想体验一下&#xff0c;让AI用你喜欢的音色为你朗读一段文字&a…...