9.【CPP】List (迭代器的模拟实现||list迭代器失效||list的模拟实现)

介绍

  1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
  2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
  3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
  4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
  5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

list迭代器的实现

普通迭代器

template<class T>struct list_node{T _data;list_node<T>* _prev;list_node<T>* _next;list_node(const T& val = T()):_prev(nullptr),_next(nullptr),_data(val){}};template<class T>struct __list_iterator{typedef list_node<T> node;typedef __list_iterator<T> iterator;node* _node;__list_iterator(node* n):_node(n){}T& operator*(){return _node->_data;}iterator& operator++(){_node = _node->_next;return *this;}iterator operator++(int){iterator tmp(*this);_node = _node->_next;return tmp;}iterator& operator--(){_node = _node->_prev;return *this;}iterator operator--(int){iterator tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const iterator& it )const{return _node != it._node;}bool operator==(const iterator& it)const{return _node == it._node;}};

const迭代器

看下面这段代码能否编译通过
在这里插入图片描述
如果传一个const对象,那么就需要实现对应的const迭代器,否则会出现权限的放大,是会报错的。
在这里插入图片描述
如果声明成这样呢?

typedef const iterator const_iterator

这是错误的。这就相当于iterator本身是const,那么就不能执行++操作,迭代器不能动还叫啥迭代器。所以我们处理的方法是返回一个const迭代器,重新实现一个const_iterator类。基本都复用普通迭代器的代码,就解引用时返回const T&。

template<class T>struct __list_const_iterator{typedef list_node<T> node;typedef __list_const_iterator<T> const_iterator;node* _node;__list_const_iterator(node* n):_node(n){}const T& operator*(){return _node->_data;}const_iterator& operator++(){_node = _node->_next;return *this;}const_iterator operator++(int){const_iterator tmp(*this);_node = _node->_next;return tmp;}const_iterator& operator--(){_node = _node->_prev;return *this;}const_iterator operator--(int){const_iterator tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const const_iterator& it)const{return _node != it._node;}bool operator==(const const_iterator& it)const{return _node == it._node;}};

这样我们代码就不报错,顺利打印出了数据

在这里插入图片描述

成员函数屁股后的const

	const iterator begin()const//后面的const修饰的是this指针指向的内容(*this),即_head本身不能被改变,指向对象的内容可变{return const iterator(_head->_next);}

改进代码

const迭代器还要去实现一个几乎相同的类,就改了个名字叫const_iterator,除了解引用返回T的引用时不同(const T&),那么我们在实现iterator迭代器类的时候加一个模版参数Ref表示引用,typedef不同的迭代器实例化不同的Ref即可解决
在这里插入图片描述
在这里插入图片描述
不得不说想出这种写法的人真的是个天才

list反向迭代器位置

在这里插入图片描述

list迭代器失效

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的**,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响**

list模拟实现代码

注意反向迭代器的实现是复用了正向迭代器

#include<iostream>
#include<cassert>namespace pqd
{template<class T>struct list_node{T _data;list_node<T>* _prev;list_node<T>* _next;list_node(const T& val = T()):_prev(nullptr),_next(nullptr),_data(val){}};template<class T,class Ref,class Ptr>struct __list_iterator{typedef list_node<T> node;typedef __list_iterator<T,Ref,Ptr> iterator;node* _node;__list_iterator(node* n):_node(n){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}iterator& operator++(){_node = _node->_next;return *this;}iterator operator++(int){iterator tmp(*this);_node = _node->_next;return tmp;}iterator& operator--(){_node = _node->_prev;return *this;}iterator operator--(int){iterator tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const iterator& it )const{return _node != it._node;}bool operator==(const iterator& it)const{return _node == it._node;}};template<class Iterator,class Ref,class Ptr>struct ReverseIterator{typedef ReverseIterator<Iterator,Ref,Ptr> Self;Iterator _cur;ReverseIterator(Iterator it):_cur(it){}Self& operator++(){--_cur;return *this;}Self& operator++(int){Iterator tmp(_cur);--_cur;return tmp;}Self& operator--(){++_cur;return *this;}Self& operator--(int){Iterator tmp(_cur);++_cur;return tmp;}Ref operator*(){Iterator tmp = _cur;--tmp;return *tmp;}bool operator!=(const Self& s){return _cur != s._cur;}};template<class T>class list{public:typedef __list_iterator<T,T&,T*> iterator;typedef __list_iterator<T,const T&,const T*> const_iterator;typedef ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<iterator, const T&, const T*> const_reverse_iterator;typedef list_node<T> node;void empty_init(){_head = new node;_head->_prev = _head;_head->_next = _head;}list(){empty_init();}template<class Iterator>list(Iterator first, Iterator last){empty_init();while (first != last){push_back(*first);++first;}}//lt2(lt1)/*list(const list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}*///现代写法void swap(list<T>& lt){std::swap(_head, lt._head);}list(const list<T>& lt){empty_init();list<T> tmp(lt.begin(), lt.end());swap(tmp);}list<T>& operator=(list<T> lt){swap(lt);return *this;}iterator begin(){return iterator(_head->_next);}const_iterator begin()const//后面的const修饰的是this指针指向的内容(*this),即_head本身不能被改变,指向对象的内容可变{return const_iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator end()const{return const_iterator(_head);}reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}void push_back(const T& val){node* tail = _head->_prev;node* newnode = new node(val);tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;}void insert(iterator pos, const T& x){node* cur = pos._node;node* prev = cur->_prev;node* newnode = new node(x);prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;}iterator erase(iterator pos){assert(pos != end());node* prev = pos._node->_prev;node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;return iterator(next);}void pop_back(){erase(--end());}void clear()//不清理头节点{iterator it = begin();while (it != end()){it=erase(it);//或者erase(it++);返回的是it++前的拷贝it++;}}~list(){clear();delete _head;_head = nullptr;}private:node* _head;};struct AA{int _a1;int _a2;AA(int a1=0,int a2=0):_a1(a1),_a2(a2){}};void test_list2(){list<AA> lt;lt.push_back(AA(1, 2));lt.push_back(AA(1, 3));lt.push_back(AA(1, 4));list<AA>::iterator it = lt.begin();while (it != lt.end()){std::cout << it->_a1 << ":" << it->_a2 << std::endl;it++;}lt.clear();}void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){std:: cout << *it << " ";++it;}}void test_list1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);print_list(lt);}void test_list3(){list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);list<int> lt2(lt1);for (auto e : lt2){std::cout << e << std::endl;}}void test_list4(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(5);auto rit =lt.rbegin();while (rit != lt.rend()){std::cout << *rit << " ";++rit;}}
}

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

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

相关文章

华为机考入门python3--(12)牛客12-字符串反转

分类&#xff1a;字符串 知识点&#xff1a; 字符串是否为空 if not my_str 字符串逆序 my_str[::-1] 题目来自【牛客】 def reverse_string(s): # 判断字符串是否为空或只包含空格 if not s.strip(): return "" # 使用Python的切片语法反转字符串 re…

Pytorch的可视化

1 使用 wandb进行可视化训练过程 本文章将从wandb的安装、wandb的使用、demo的演示进行讲解。 1.1 如何安装wandb&#xff1f; wandb的安装比较简单&#xff0c;在终端中执行如下的命令即可&#xff1a; pip install wandb在安装完成之后&#xff0c;我们需要&#xff0c;去…

matlab入门,在线编辑,无需安装matab

matlab相关教程做的很完善&#xff0c;除了B站看看教程&#xff0c;官方教程我觉得更加高效。跟着教程一步一步编辑&#xff0c;非常方便。 阅读 MATLAB 官方教程&#xff1a; MATLAB 官方教程提供了从基础到高级的教学内容&#xff0c;内容包括 MATLAB 的基本语法、数据处理…

Vue3高频知识点和写法

一 Vue插件 二 vue3项目创建 创建完成后npm install npm run dev 三 setup 一 响应式数据 setup函数是用来代替data和methods的写法的&#xff0c;在setup函数中声明的数据和函数&#xff0c;导出后可以在页面中使用。 但是暂时不是响应式数据&#xff0c;如果要响应式数据的…

C++笔记1:操纵符输入输出

C操纵符用来控制输出控制&#xff0c;一是输出的形式&#xff0c;二是控制补白的数量和位置。本文记录一下&#xff0c;在一些笔试的ACM模式可能有用。其中1-4节的部分是关于格式化输入输出操作&#xff0c;5-6节的部分是关于未格式化输入输出操作。 1. 控制布尔值的格式 一般…

C语言—基础数据类型(含进制转换)

进制转换不多&#xff0c;但我觉得适合小白(我爱夸自己嘿嘿) 练习 1. 确认基础类型所占用的内存空间(提示&#xff1a;使用sizeof 运算符)&#xff1a; 在这里我说一下&#xff0c;long 类型通常占用 4 字节。在 64 位系统上&#xff0c;long 类型通常也可为 8 字节。 格式…

LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】

文章目录 前言LeetCode、208. 实现 Trie (前缀树)【中等&#xff0c;自定义数据结构】题目链接与分类思路 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领…

低资源学习与知识图谱:构建与应用

目录 前言1 低资源学习方法1.1 数据增强1.2 特征增强1.3 模型增强 2 低资源知识图谱构建与推理2.1 元关系学习2.2 对抗学习2.3 零样本关系抽取2.4 零样本学习与迁移学习2.5 零样本学习与辅助信息 3 基于知识图谱的低资源学习应用3.1 零样本图像分类3.2 知识增强的零样本学习3.3…

云原生介绍与容器的基本概念

云原生介绍 1、云原生的定义 云原生为用户指定了一条低心智负担的、敏捷的、能够以可扩展、可复制的方式最大化地利用云的能力、发挥云的价值的最佳路径。 2、云原生思想两个理论 第一个理论基础是&#xff1a;不可变基础设施。 第二个理论基础是&#xff1a;云应用编排理…

备战蓝桥杯---图论基础理论

图的存储&#xff1a; 1.邻接矩阵&#xff1a; 我们用map[i][j]表示i--->j的边权 2.用vector数组&#xff08;在搜索专题的游戏一题中应用过&#xff09; 3.用邻接表&#xff1a; 下面是用链表实现的基本功能的代码&#xff1a; #include<bits/stdc.h> using nam…

纪念一下 开始写博客两周以来第一次入围榜单

两周里 创作博客 第一次进入热榜 虽然只有几十名 但也算是一个突破 确实没想到自己随便做的笔记就入围了 感谢各位大佬的支持&#xff01;继续进步&#xff01;&#x1f973;&#x1f973;&#x1f973;

服务流控(Sentinel)

引入依赖 <!-- 必须的 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><!-- sentinel 核心库 --> <dependency><groupId>com.ali…

权限系统设计

权限系统设计 RBAC 基于角色的访问控制 ABAC 基于属性的访问控制 普通的系统无非 CRUD&#xff0c;那系统如何控制一个用户该看到哪些数据、能操作哪些功能&#xff1f;日常开发中最常用到 RBAC 和 OAuth2 这两种访问控制和授权方案 RBAC 基于角色的访问控制 所有的访问控制模…

力扣精选算法100道——【模板】前缀和 (二维)

目录 &#x1f388;题目解析 &#x1f388;算法原理 &#x1f388;实现代码 二维前缀和【模板】 &#x1f388;题目解析 上一题我们讲述了一维的前缀和求法。 第一行三个参数&#xff0c;n是行数3&#xff0c;m是列数4&#xff0c;q3代表查询次数 接下来就是n行m列的矩阵…

基于python混沌系统敏感文本信息加密算法的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

微服务OAuth 2.1认证授权Demo方案(Spring Security 6)

文章目录 一、介绍二、auth微服务代码1. SecurityConfig2. UserDetailsService3. 总结 三、gateway微服务代码1. 统一处理CORS问题 四、content微服务代码1. controller2. SecurityConfig3. 解析JWT Utils4. 总结 五、一些坑 书接上文 微服务OAuth 2.1认证授权可行性方案(Sprin…

【51单片机】串口(江科大)

8.1串口通信 1.串口介绍 2.硬件电路 3.电平标准 电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种: 电平标准是数据1和数据O的表达方式,是传输线缆中人为规定的电 压与数据的对应关系,串口常用的电平标准有如下…

【QT+QGIS跨平台编译】之三十六:【RasterLite2+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、RasterLite2介绍二、文件下载三、文件分析四、pro文件五、编译实践一、RasterLite2介绍 RasterLite2是一个开源的轻量级栅格数据库,可以用于存储和管理各种类型的栅格数据,包括卫星遥感图像、数字高程模型等。 与传统的GIS数据存储方式不同,RasterLite2采用基…

React18原理: 时间分片技术选择

渲染1w个节点的不同方式 1 &#xff09;案例1&#xff1a;一次渲染1w个节点 <div idroot><div><script type"text/javascript">function randomHexColor() {return "#" ("0000" (Math.random() * 0x1000000 << 0).toS…

【深蓝学院】移动机器人运动规划--第4章 动力学约束下的运动规划--作业

文章目录 1. T11.1 题目1.2 求解1.3 Pontryagin Minimum Principle 的拓展 2. T22.1 题目2.2 求解 3. Reference 1. T1 1.1 题目 1.2 求解 1.3 Pontryagin Minimum Principle 的拓展 2. T2 2.1 题目 2.2 求解 Listing1&#xff1a; demo_node.cpp/trajectoryLibrary() for(i…