C++List模拟实现|细节|难点|易错点|全面解析|类型转换|

目录

1.模拟代码全部

2.四大块代码理解

1.最底层:ListNode部分

2.第二层:ListIterator部分

3.第三层:ReserveListIterator部分

 4最终层:List


1.模拟代码全部

using namespace std;
template<class T>
struct ListNode
{T _Val;ListNode<T>* Prev;ListNode<T>* Next;ListNode(T Val=T()){Prev = nullptr;Next = nullptr;_Val = Val;}
};
template<class T, class Ref, class Ptr>
class ListIterator
{
public:typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;typedef Ref Ref;typedef Ptr Ptr;ListIterator(Node* _NODE = nullptr) :_node(_NODE){}Ptr operator->(){return &(operator*());}Ref operator*(){return _node->_Val;}Self& operator++(){_node = _node->Next;return *this;}Self operator++(int){Node* Newnode = _node;_node = _node->Next;return Newnode;}Self& operator--(){_node = _node->Prev;return *this;}Self operator--(int){Node* Newnode = _node;_node = _node->Prev;return Newnode;}bool operator==(const Self& I) const{if (I._node == _node){return true;}else{return false;}}bool operator!=(const Self& I)const{if (I._node != _node){return true;}else{return false;}}Node* _node;
};
template<class Iterator>
class ReserveListIterator
{
public:typedef typename Iterator::Ptr Ptr;typedef typename Iterator::Ref Ref;typedef ReserveListIterator<Iterator> Self;ReserveListIterator(Iterator it):_it(it){}Ref operator*(){Iterator temp(_it);temp--;return *temp;}Ptr operator->(){return &(operator*());}Self operator++(){_it++;return *this;}Self operator++(int){Iterator temp(_it);_it++;return *temp;}Self operator--(){_it--;return *this;}Self operator--(int){Iterator temp(_it);_it--;return *temp;}bool operator == (const Self & I) const{if (I._it==_it){return true;}else{return false;}}bool operator !=(const Self& I)const{if (I._it != _it){return true;}else{return false;}}Iterator _it;
};
template<class T>
class List
{typedef ListNode<T> Node;typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;typedef ReserveListIterator<iterator> reverse_iterator;typedef ReserveListIterator<const_iterator> const_reverse_iterator;
public:List(){creathead();}List(int n,const T& Value=T()){creathead();for (int i = 0; i < n; i++){push_back(Value);}}template <class Iterator>List(Iterator first, Iterator last){creathead();while (first != last){push_back(*first);first++;}}List(const List<T>& l){creathead();List<T>temp(l.begin(), l.end());this->swap(temp);}List<T>& operator=(List<T> l){List<T>temp(l);this->swap(temp);return *this;}~List(){clear();delete _head;_head = nullptr;}iterator begin(){return _head->Next;}iterator end(){return _head;}const_iterator begin()const{return _head->Next;}const_iterator end()const{return _head;}reverse_iterator rbegin(){return reverse_iterator(begin());}reverse_iterator rend(){return reverse_iterator(end());}const_reverse_iterator rbegin()const{return const_reverse_iterator(begin());}const_reverse_iterator rend()const{return const_reverse_iterator(end());}size_t size()const{size_t num = 0;Node* CUR = _head->Next;while (CUR != _head){num++;CUR = CUR->Next;}return num;}bool empty()const{if (begin() == end()){return true;}else{return false;}}void resize(size_t newsize, const T& data = T()){if (newsize > size()){Node* it = end();it = it->Prev;for (size_t i = size(); i < newsize; i++){Node* cur = new Node(data);cur->Next = it->Next;cur->Prev = it;it->Next = cur;}}else{Node* it = end();size_t len = size() - newsize;while (len--){Node* cur = it;it = it->Prev;delete cur;}it->Next = _head;_head->Prev = it;}}T& front(){return *begin();}const T& front()const{return *begin();}T& back(){iterator it = end();it--;return *it;}const T& back()const{iterator it = end();it--;return *it;}void push_back(const T& val){Node* Newnode = new Node(val);Node* cur = _head->Prev;cur->Next = Newnode;_head->Prev = Newnode;Newnode->Next = _head;Newnode->Prev = cur;}void pop_back(){Node* cur = _head->Prev->Prev;Node* popnode = _head->Prev;cur->Next = _head;_head->Prev = cur;delete popnode;}void push_front(const T& val){Node* cur = _head->Next;Node* newnode = new Node(val);_head->Next = newnode;cur->Prev = newnode;newnode->Next = cur;newnode->Prev = _head;}void pop_front(){Node* cur = _head->Next->Next;Node* popnode = _head->Next;_head->Next = cur;cur->Prev = _head;delete popnode;}iterator insert(iterator pos, const T& val){Node* pre = pos._node->Prev;Node* nect = pos._node;Node* newnode = new Node(val);newnode->Prev = pre;newnode->Next = nect;pre->Next = newnode;nect->Prev = newnode;return newnode;}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->Prev;Node* next = cur->Next;delete cur;prev->Next = next;next->Prev = prev;return next;}void clear(){size_t sz = this->size();while (sz--){Node* cur = _head->Next;Node* pop;}}void swap(List<T>& l){Node* temp = l._head;l._head = _head;_head = temp;}void creathead(){_head = new Node(0);_head->Prev = _head;_head->Next = _head;}
private:Node* _head;
};

2.四大块代码理解

代码一共分为四块,我们分开来理解

1.最底层:ListNode部分

这里是最简单的部分,小伙伴们应该都看的懂吧

using namespace std;
template<class T>
struct ListNode
{T _Val;ListNode<T>* Prev;ListNode<T>* Next;ListNode(T Val=T()){Prev = nullptr;Next = nullptr;_Val = Val;}
};

 这里我们形象点记忆

其实应该不用赘述多了,基础好的同学看到这张图应该就差不多懂了。 

唯一要注意的是

T Val=T()

>>    T()表示对类型T进行值初始化,生成一个临时的右值

>>    如果T是内置类型(如int,double,char等),则T()会执行零初始化,即返回0,0.0或'\0'等默认值。

>>    如果T是类类型,则T()会调用默认构造函数(如果存在)

聪明的小伙伴已经理解清楚了

2.第二层:ListIterator部分

聪明的小伙伴应该看代码就能懂了

那么我在这下方陈述了一些难点和易错点 

template<class T, class Ref, class Ptr>
class ListIterator
{
public:typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;typedef Ref Ref;typedef Ptr Ptr;ListIterator(Node* _NODE = nullptr) :_node(_NODE){}Ref operator*(){return _node->_Val;}Self& operator++(){_node = _node->Next;return *this;}Self operator++(int){Node* Newnode = _node;_node = _node->Next;return Newnode;}Self& operator--(){_node = _node->Prev;return *this;}Self operator--(int){Node* Newnode = _node;_node = _node->Prev;return Newnode;}bool operator==(const Self& I) const{if (I._node == _node){return true;}else{return false;}}bool operator!=(const Self& I)const{if (I._node != _node){return true;}else{return false;}}Node* _node;
};

聪明的小伙伴应该看代码就能懂了

那么我在这陈述一下一些难点和易错点 

>>    typedef Ref Ref和typedef Ptr Ptr,简单来说,我们需要让编译器知道Listiterator里面有Ptr和 Ref,后面的反向迭代器ReserveListIterator来使用Listiterator的Ref和Ptr

>>    Ref:Ref在后面我们会通过T&来填充这块模板,也就是说Ref就是引用

>>    Ptr:Ptr在后面我们会通过T*来填充这块模板,也就是说Ptr就是指针

3.第三层:ReserveListIterator部分

聪明的小伙伴直接看代码

template<class Iterator>
class ReserveListIterator
{
public:typedef typename Iterator::Ptr Ptr;typedef typename Iterator::Ref Ref;typedef ReserveListIterator<Iterator> Self;ReserveListIterator(Iterator it):_it(it){}Ref operator*(){Iterator temp(_it);temp--;return *temp;}Ptr operator->(){return &(operator*());}Self operator++(){_it++;return *this;}Self operator++(int){Iterator temp(_it);_it++;return *temp;}Self operator--(){_it--;return *this;}Self operator--(int){Iterator temp(_it);_it--;return *temp;}bool operator == (const Self & I) const{if (I._it==_it){return true;}else{return false;}}bool operator !=(const Self& I)const{if (I._it != _it){return true;}else{return false;}}Iterator _it;
};

 

>>    之前我们在ListIterator里重新定义了Ptr和Ref参数就是留在ReserveListIterator使用

 

这里要注意一定不要写成Iterator &,本人之前就因为这个错误导致费了1小时/(ㄒoㄒ)/~~ 

 4最终层:List

牛人已经看代码就懂了

template<class T>
class List
{typedef ListNode<T> Node;typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;typedef ReserveListIterator<iterator> reverse_iterator;typedef ReserveListIterator<const_iterator> const_reverse_iterator;
public:List(){creathead();}List(int n,const T& Value=T()){creathead();for (int i = 0; i < n; i++){push_back(Value);}}template <class Iterator>List(Iterator first, Iterator last){creathead();while (first != last){push_back(*first);first++;}}List(const List<T>& l){creathead();List<T>temp(l.begin(), l.end());this->swap(temp);}List<T>& operator=(List<T> l){List<T>temp(l);this->swap(temp);return *this;}~List(){clear();delete _head;_head = nullptr;}iterator begin(){return _head->Next;}iterator end(){return _head;}const_iterator begin()const{return _head->Next;}const_iterator end()const{return _head;}reverse_iterator rbegin(){return reverse_iterator(begin());}reverse_iterator rend(){return reverse_iterator(end());}const_reverse_iterator rbegin()const{return const_reverse_iterator(begin());}const_reverse_iterator rend()const{return const_reverse_iterator(end());}size_t size()const{size_t num = 0;Node* CUR = _head->Next;while (CUR != _head){num++;CUR = CUR->Next;}return num;}bool empty()const{if (begin() == end()){return true;}else{return false;}}void resize(size_t newsize, const T& data = T()){if (newsize > size()){Node* it = end();it = it->Prev;for (size_t i = size(); i < newsize; i++){Node* cur = new Node(data);cur->Next = it->Next;cur->Prev = it;it->Next = cur;}}else{Node* it = end();size_t len = size() - newsize;while (len--){Node* cur = it;it = it->Prev;delete cur;}it->Next = _head;_head->Prev = it;}}T& front(){return *begin();}const T& front()const{return *begin();}T& back(){iterator it = end();it--;return *it;}const T& back()const{iterator it = end();it--;return *it;}void push_back(const T& val){Node* Newnode = new Node(val);Node* cur = _head->Prev;cur->Next = Newnode;_head->Prev = Newnode;Newnode->Next = _head;Newnode->Prev = cur;}void pop_back(){Node* cur = _head->Prev->Prev;Node* popnode = _head->Prev;cur->Next = _head;_head->Prev = cur;delete popnode;}void push_front(const T& val){Node* cur = _head->Next;Node* newnode = new Node(val);_head->Next = newnode;cur->Prev = newnode;newnode->Next = cur;newnode->Prev = _head;}void pop_front(){Node* cur = _head->Next->Next;Node* popnode = _head->Next;_head->Next = cur;cur->Prev = _head;delete popnode;}iterator insert(iterator pos, const T& val){Node* pre = pos._node->Prev;Node* nect = pos._node;Node* newnode = new Node(val);newnode->Prev = pre;newnode->Next = nect;pre->Next = newnode;nect->Prev = newnode;return newnode;}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->Prev;Node* next = cur->Next;delete cur;prev->Next = next;next->Prev = prev;return next;}void clear(){size_t sz = this->size();while (sz--){Node* cur = _head->Next;Node* pop;}}void swap(List<T>& l){Node* temp = l._head;l._head = _head;_head = temp;}void creathead(){_head = new Node(0);_head->Prev = _head;_head->Next = _head;}
private:Node* _head;
};

 这里要注意一下转换顺序,listnode不能直接转换为reverse_iterator 

listnode转换为reverse_iterator需要两个个过程

 

 易错点难点就是以上那么多了,说多了只会妨碍小伙伴们,通过自己学习效率才是最高的。

3.测试代码 

#include"LList.h"
#include<iostream>
void ListPrint(List<int> it)
{auto i = it.begin();while(i!=it.end()){cout << *i << " ";i++;}
}
void TestBiteList1()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };List<int> l3(array, array + sizeof(array) / sizeof(array[0]));ListPrint(l3);ListIterator<int, int&, int*> it(l3.begin());}
void TestBiteList2()
{List<int> l;l.push_back(1);l.push_back(2);l.push_back(3);ListPrint(l);l.pop_back();l.pop_back();ListPrint(l);l.pop_back();cout << l.size() << endl;l.push_front(1);l.push_front(2);l.push_front(3);ListPrint(l);l.pop_front();l.pop_front();ListPrint(l);l.pop_front();cout << l.size() << endl;
}
void TestBiteList3()
{int array[] = { 1, 2, 3, 4, 5 };List<int> l(array, array + sizeof(array) / sizeof(array[0]));auto pos = l.begin();l.insert(l.begin(), 0);ListPrint(l);++pos;l.insert(pos, 2);ListPrint(l);l.erase(l.begin());l.erase(pos);ListPrint(l);cout << *pos << endl;auto it = l.begin();while (it != l.end()){it = l.erase(it);}cout << l.size() << endl;
}
void TestBiteList4()
{int array[] = { 1, 2, 3, 4, 5 };List<int> l(array, array + sizeof(array) / sizeof(array[0]));auto rit = l.rbegin();while (rit != l.rend()){cout << *rit << " ";++rit;}cout << endl;const List<int> cl(l);auto crit = l.rbegin();while (crit != l.rend()){cout << *crit << " ";++crit;}cout << endl;
}
int main()
{TestBiteList1();TestBiteList2();TestBiteList3();TestBiteList4();
}

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

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

相关文章

【深度学习与实战】2.1、线性回归模型与梯度下降法先导

import numpy as np# 数据准备 X np.array([1, 2, 3]) y np.array([3, 5, 7])# 参数初始化 w0, w1 0, 0 alpha 0.1 n len(X)# 迭代10次 for epoch in range(10):# 计算预测值y_pred w1 * X w0# 计算梯度grad_w0 (1/n) * np.sum(y_pred - y)grad_w1 (1/n) * np.sum((y_…

锐捷EWEB路由器 timeout.php任意文件上传漏洞代码审计(DVB-2025-9003)

免责声明 仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 一:产品介绍 锐捷EWEB路由器是锐…

flask开发中设置Flask SQLAlchemy 的 db.Column 只存储非负整数(即 0 或正整数)

如果你想控制一个 Flask SQLAlchemy 的 db.Column 只存储非负整数&#xff08;即 0 或正整数&#xff09;&#xff0c;你可以在模型中使用验证来确保这一点。一种常见的方法是使用模型的 validate 方法或者在执行插入或更新操作时进行检查。 以下是实现这一目标的几种方法&…

sqlmap 源码阅读与流程分析

0x01 前言 还是代码功底太差&#xff0c;所以想尝试阅读 sqlmap 源码一下&#xff0c;并且自己用 golang 重构&#xff0c;到后面会进行 ysoserial 的改写&#xff1b;以及 xray 的重构&#xff0c;当然那个应该会很多参考 cel-go 项目 0x02 环境准备 sqlmap 的项目地址&…

vscode连接服务器失败问题解决

文章目录 问题描述原因分析解决方法彻底删除VS Code重新安装较老的版本 问题描述 vscode链接服务器时提示了下面问题&#xff1a; 原因分析 这是说明VScode版本太高了。 https://code.visualstudio.com/docs/remote/faq#_can-i-run-vs-code-server-on-older-linux-distribu…

企业网站源码HTML成品网站与网页代码模板指南

在当今数字化时代&#xff0c;企业网站已成为展示品牌形象、吸引客户和提供在线服务的重要工具。对于许多企业来说&#xff0c;使用现成的HTML网站源码模板是快速搭建网站的高效方式。本文将详细介绍企业网站源码、HTML成品网站以及网页代码模板的相关内容&#xff0c;帮助你快…

计算机网络 - OSI 七层模型

OSI 七层模型 OSI&#xff08;Open System Interconnection&#xff0c;开放系统互联&#xff09;模型由 ISO&#xff08;国际标准化组织&#xff09; 制定&#xff0c;目的是为不同计算机网络系统之间的通信提供一个标准化的框架。它将网络通信划分为 七个层次&#xff0c;每…

flutter-实现瀑布流布局及下拉刷新上拉加载更多

文章目录 1. 效果预览2. 结构分析3. 完整代码4. 总结 1. 效果预览 在 Flutter 应用开发中&#xff0c;瀑布流布局常用于展示图片、商品列表等需要以不规则但整齐排列的内容。同时&#xff0c;下拉刷新和上拉加载更多功能&#xff0c;能够极大提升用户体验&#xff0c;让用户方…

在 Ubuntu 下通过 Docker 部署 Nginx 服务器

1. Docker 和 Nginx 简介以及实验环境 Docker 是一个开源的容器化平台&#xff0c;允许开发者将应用程序及其依赖项打包成一个轻量级的、可移植的容器。通过 Docker&#xff0c;开发者可以在任何支持 Docker 的环境中运行应用&#xff0c;从而实现一致的开发和生产环境。Docke…

IoT平台实时监测机器人状态的实现方案

通过IoT平台实时监测机器人状态的实现方案与可执行路径 一、整体架构设计 #mermaid-svg-6xMlDfFSZM4Wc8tA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6xMlDfFSZM4Wc8tA .error-icon{fill:#552222;}#mermaid-sv…

mybatis里in关键字拼接id问题

我们一般会把ids集合用StrUtil.join(‘,’)转成"1,2,3"这种形式 然后放入in中 我们会这么写: select id, nick_name, icon from tb_user where id in (#{ids}) order by FIELD(id, #{ids})结果发现sql执行是这样的: select id, nick_name, icon from tb_user where…

4.用 Excel 录入数据

一 用 Excel 录入数据的两种方式 用鼠标键盘录入数据和从网上爬取数据。 二 用鼠标键盘录入数据 1.录入数据的规范 横着录入数据&#xff08;横着一条条录入数据&#xff09;。 2.使用快捷键进行数据录入 tab 键和 enter 键。 tab 键&#xff1a;向右移动一个单元格。 tab 键…

C++类与对象-3.23笔记

今天学习了类的概述和写类的基本框架 在哔哩哔哩学习的这个老师的C面向对象高级语言程序设计教程&#xff08;118集全&#xff09;讲的很不错&#xff08;真的&#xff01;&#xff01;&#xff01;&#xff09;&#xff0c;C语言也是在这个老师的带领下学习的 #include<io…

Android读写权限分析

Android系统使用的是Linux内核&#xff0c;所以Android系统沿用了linux系统的那一套文件读写权限。 目录 1&#xff0c;权限解读1.1&#xff0c;权限分为三种类型&#xff1a;1.2&#xff0c;权限针对的三类对象&#xff1a;1.3&#xff0c;文件和目录的权限区别1.3.1&#xf…

Python二分查找【清晰易懂】

1. 二分查找是什么&#xff1f; 想象你在玩“猜数字”游戏&#xff1a; 对方心里想一个 1~100 的数字&#xff0c;你每次猜一个数&#xff0c;对方会告诉你是“大了”还是“小了”。 最快的方法&#xff1a;每次都猜中间的数&#xff01;比如第一次猜50&#xff0c;如果大了&…

关于Qt的各类问题

目录 1、问题&#xff1a;Qt中文乱码 2、问题&#xff1a;启动时避免ComBox控件出现默认值 博客会不定期的更新各种Qt开发的Bug与解决方法,敬请关注! 1、问题&#xff1a;Qt中文乱码 问题描述&#xff1a;我在设置标题时出现了中文乱码 this->setWindowTitle("算法…

关于我对接了deepseek之后部署到本地将数据存储到mysql的过程

写在前面 今天写一下使用nodejs作为服务端&#xff0c;vue作为客户端&#xff0c;mysql的数据库&#xff0c;对接deepseek的全过程&#xff0c;要实现一个很简单的效果就是&#xff0c;可以自由的询问&#xff0c;然后可以将询问的过程存储到mysql的数据库中。 文档对接 deeps…

游戏引擎学习第182天

回顾和今天的计划 昨天的进展令人惊喜&#xff0c;原本的调试系统已经被一个新的系统完全替换&#xff0c;新系统不仅能完成原有的所有功能&#xff0c;还能捕获完整的调试信息&#xff0c;包括时间戳等关键数据。这次的替换非常顺利&#xff0c;效果很好。 今天的重点是在此基…

CSS终极指南:从基础到高级实践

目录 一、CSS基础概念与核心语法 1.1 CSS的本质与作用 1.2 CSS语法结构 二、CSS与HTML结合的四种方式 2.1 内联样式&#xff08;Inline Style&#xff09; 2.2 内部样式表&#xff08;Internal Style Sheet&#xff09; 2.3 外部样式表&#xff08;External Style Sheet…

MATLAB 2024b深度学习新特性全面解析与DeepSeek大模型集成开发

MATLAB 2024b深度学习工具箱通过架构创新与功能强化&#xff0c;为科研创新和行业应用提供了全栈式解决方案。 第一&#xff1a;MATLAB 2024b深度学习工具箱新特性 1、MATLAB Deep Learning Toolbox 2、实时脚本&#xff08;Live Script&#xff09;与交互控件&#xff08…