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.rhkb.cn/news/39268.html

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

相关文章

如何让自动驾驶汽车“看清”世界?坐标映射与数据融合概述

在自动驾驶领域,多传感器融合技术是实现车辆环境感知和决策控制的关键。其中,坐标系映射和对应是多传感器融合的重要环节,它涉及到不同传感器数据在统一坐标系下的转换和匹配,以实现对车辆周围环境的准确感知。本文将介绍多传感器融合中坐标系映射和对应的数学基础和实际应…

鸿蒙开发之背景图片的使用

在鸿蒙开发中&#xff0c;设置背景图片是提升应用界面视觉效果的重要一环。以下是关于鸿蒙开发中背景图片使用的详细方法&#xff1a; 一、通过XML布局文件设置背景图片 1.使用Image组件设置背景图片 在XML布局文件中&#xff0c;可以使用Image组件来设置背景图片。通过ohos…

如何在 HTML 中创建一个有序列表和无序列表,它们的语义有何不同?

大白话如何在 HTML 中创建一个有序列表和无序列表&#xff0c;它们的语义有何不同&#xff1f; 1. HTML 中有序列表和无序列表的基本概念 在 HTML 里&#xff0c;列表是一种用来组织信息的方式。有序列表就是带有编号的列表&#xff0c;它可以让内容按照一定的顺序呈现&#…

c++malloc出来的对象调用构造-------定位new

前言:之前在搓高并发内存池的时候就在想,类对象不能调用自身的构造函数,那直接申请内存出来的类对象岂不是很难受,然后我这两天仔细研究了一下,发现其实构造函数也可以显示去调用,而且含不限量,故做此文 在c中一个类对象不能直接调用自身的构造 class A { public:A() {cout &l…

ElementUI时间选择、日期选择

如大家所发现的&#xff0c;由于ElementUI 时间选择器&#xff0c;日期选择器&#xff0c;时间日期选择器点击清除按钮时&#xff0c;v-model 所绑定的属性值会变成 null&#xff0c;所以当使用 ElementUI 时间选择器&#xff0c;日期选择器&#xff0c;时间日期选择器 时&…

一篇文章入门Python Flask框架前后端数据库开发实践(pycharm在anaconda环境下)

Python Flask 是一个轻量级的 Web 应用框架&#xff0c;也被称为微框架。它以简洁、灵活和易于上手的特点而受到开发者的喜爱。 核心特点 轻量级&#xff1a;Flask 核心代码简洁&#xff0c;仅包含 Web 开发的基本功能&#xff0c;不强制使用特定的数据库、模板引擎等&#xf…

ctfshow WEB web2

1.查当前数据库名称 or 11 union select 1,database(),3 limit 1,2;#-- 得到数据库名称web2 2.查看数据库表的数量 or 11 union select 1,(select count(*) from information_schema.tables where table_schema web2),3 limit 1,2;#-- 得到数据库表数量为2 3.查表的名字 第…

【Git】--- 分支管理

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; Git 本篇博客我们来介绍Git的一个重要功能之一 ---- 分支。我们将讲解关于分支的各种操作&#xff0c;以及如何帮助我们进行开发。 &#x1f3e0; 理解分支…

系统思考与心智模式

“问题不是出在我们做了多少&#xff0c;而是出在我们做了什么。” — 赫尔曼凯恩 “一分耕耘一分收获”&#xff0c;这似乎是我们脑海中根深蒂固的心智模式。今天&#xff0c;我在一家餐厅用餐&#xff0c;店员告诉我&#xff0c;打卡收藏可以获得一份小食。没过多久&#xf…

纯文本驱动的数据可视化革命——AI生成图表「图表狐」全场景深度解析

一、技术架构重定义 图表狐核心能力边界 ✅ 纯文本输入&#xff1a;支持任意格式文字描述&#xff08;会议纪要/邮件/手写笔记&#xff09; ✅ 智能解析引擎&#xff1a; 实体识别&#xff08;数值/时间/分类维度&#xff09; 语义纠错&#xff08;自动修复错别字/单位混乱&…

多线程 --- 进程和线程的基本知识

进程 前面我们提到了一个概念是&#xff0c;多任务操作系统&#xff0c;即希望该系统能够同时运行多个程序。本质上说&#xff0c;进程&#xff0c;就算用来解决”并发编程“这样的问题的。 在一些特定的情况下&#xff0c;进程的表现&#xff0c;其实并不能很好的解决”并发…

SCI英文论文Accepted后的第一步——Rights and Access

SCI英文论文Accepted后的第一步——Rights and Access 目录 SCI英文论文Accepted后的第一步——Rights and AccessBased on information provided the embargo period/end date is 24 months. 因为选择闭源**Rights and Access(版权与访问权限)**环节是关键第一步,具体操作流…

流程控制语句

python中的流程控制语句有三种&#xff0c;顺序结构、条件结构和循环结构 1&#xff09;顺序结构&#xff1a; 从上往下&#xff0c;从左到右&#xff0c;依次逐行执行。 #顺序结构python print(start) print(hello world1 ) print(hello world2 ) print(hello world3 ) pri…

2.4 关键路径法

项目进度管理核心工具全解析 &#x1f680; 一、关键路径法&#xff08;CPM&#xff09;精要 1. 核心概念图解 #mermaid-svg-5MOABZm9lR8A53ss {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-5MOABZm9lR8A53ss .e…

Unity 实现一个简易可拓展性的对话系统

本人能力有限,一切实现仅供参考,如有不足还请斧正 起因是我看到学校社团内有人做了对话系统的分享,我想了想之前没写过这种东西,而Fungus插件教程太老了,NodeCanvas插件学习成本又比较高,我就干脆寻找资料 加上自己迭代一下,花了一天时间完成了这个对话系统 目录 1.介绍 2.核…

架构思维:通用系统设计方法论_从复杂度分析到技术实现指南

文章目录 Question订单履约原始架构痛点目标架构架构图说明关键设计点优点 设计方法论复杂来源解决方案评估标准从设计原则出发 技术实现 &#xff08;以选型Redis为例&#xff09;Redis消息队列的实现细节高可用设计 总结 Question 我们经常聊如何设计一个比较完善的系统&…

llama源码学习·model.py[7]Transformer类

一、源码展示 class Transformer(nn.Module):def __init__(self, params: ModelArgs):super().__init__()self.params paramsself.vocab_size params.vocab_sizeself.n_layers params.n_layersself.tok_embeddings VocabParallelEmbedding(params.vocab_size, params.dim,…

MD2Card(markdown)

MD2Card 介绍&#xff1a; 1.小红书爆款神器&#xff0c;Markdown笔记秒转高颜值卡片 2.实时预览15种主题&#xff0c;自动拆长文&#xff0c;图片/SVG导出即用 3.零门槛不登录&#xff0c;免费无限生成&#xff0c;专治排版废和设计手残党 网站地址&#xff1a; https://md2…

第二节第一部分:String字符串

一、导包 二、String字符串 三、String注意事项 四、字符串的比较 五、面试例题 六、String案例一 需求分析&#xff1a; 代码&#xff1a; package com.StringTest;import java.util.Scanner;public class StingTest {public static void main(String[] args) {//1.开发一个…

动态规划(01背包恰好装满型详解):和为目标值的最长子序列长度

0-1背包&#xff1a;有n个物品&#xff0c;第i个物品的体积为w[i]&#xff0c;价值为v[i]&#xff0c;每个物品至多选择一个&#xff0c;求体积和不超过capacity的最大价值和。 对于第i个物品&#xff0c;我们只有两种选择&#xff1a;选&#xff0c;或者不选。如果选&#xf…