【STL十三】适配器——迭代器适配器

news2024/11/20 6:37:20

【STL十二】适配器——迭代器适配器

  • 一、迭代器
    • 1、迭代器分类
    • 2、迭代器定义
    • 3、迭代器和迭代器适配器
  • 二、迭代器适配器、流迭代器
    • 1、简介
    • 2、迭代器适配器
    • 3、流迭代器
  • 三、反向迭代器
    • 1、简介
    • 2、模板类
    • 3、demo
  • 四、插入迭代器
    • 1、简介
    • 2、模板类
    • 3、demo
  • 五、移动迭代器
    • 1、简介
    • 2、模板类
    • 3、demo
  • 六、流迭代器
    • 1、简介
    • 2、模板类
    • 3、demo
  • 七、流缓冲区迭代器
    • 1、简介
    • 2、模板类
    • 3、demo

一、迭代器

无论是序列容器还是关联容器,它们本质上都是用来存储大量数据的。诸如数据的排序、查找、求和、插入等需要对数据进行遍历的操作方法应该是类似的。而实现此操作,多数情况会选用“迭代器(iterator)”来实现。

它除了要具有对容器进行遍历读写数据的能力之外,还要能对外隐藏容器的内部差异,从而以统一的界面向算法传送数据。

  • 迭代器是一个“可遍历STL容器全部或部分元素”的对象.

1、迭代器分类

  • 迭代器:输入迭代器、输出迭代器、正向迭代器、双向迭代器或者随机访问迭代器

STL 标准库为每一种标准容器定义了一种迭代器类型,这意味着,不同容器的迭代器也不同,其功能强弱也有所不同。

常用的迭代器按功能强弱分为输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器 5 种。本节主要介绍后面的这 3 种迭代器。

    1. 前向迭代器(forward iterator)
      假设 p 是一个前向迭代器,则 p 支持 ++p,p++,*p 操作,还可以被复制或赋值,可以用 == 和 != 运算符进行比较。此外,两个正向迭代器可以互相赋值。
    1. 双向迭代器(bidirectional iterator)
      双向迭代器具有正向迭代器的全部功能,除此之外,假设 p 是一个双向迭代器,则还可以进行 --p 或者 p-- 操作(即一次向后移动一个位置)。
    1. 随机访问迭代器(random access iterator)
      随机访问迭代器具有双向迭代器的全部功能。除此之外,假设 p 是一个随机访问迭代器,i 是一个整型变量或常量,则 p 还支持以下操作:
      p+=i:使得 p 往后移动 i 个元素。
      p-=i:使得 p 往前移动 i 个元素。
      p+i:返回 p 后面第 i 个元素的迭代器。
      p-i:返回 p 前面第 i 个元素的迭代器。
      p[i]:返回 p 后面第 i 个元素的引用。
容器对应的迭代器类型
array随机访问迭代器
vector随机访问迭代器
deque随机访问迭代器
list双向迭代器
set / multiset双向迭代器
map / multimap双向迭代器
forward_list前向迭代器
unordered_map / unordered_multimap前向迭代器
unordered_set / unordered_multiset前向迭代器
stack不支持迭代器
queue不支持迭代器

2、迭代器定义

尽管不同容器对应着不同类别的迭代器,但这些迭代器有着较为统一的定义方式,具体分为 4 种,

迭代器定义方式具体格式
正向迭代器容器类名::iterator 迭代器名;
常量正向迭代器容器类名::const_iterator 迭代器名;

以上每种容器对应的迭代器,我们基本都用过了,就不再重复的说了。

3、迭代器和迭代器适配器

  • 从以下截图我们可以看到,输入迭代器、输出迭代器、正向迭代器、双向迭代器或者随机访问迭代器真正实现是在c++20中,
  • vector::iterator ite;虽然我们平时这样定义也是返回一个随机访问迭代器。但是每个迭代器从字面区分开来,确是在c++20中。(同理同样方法定义的list、set、map返回的也确实是双向迭代器)
  • 输入迭代器、输出迭代器,也是在c++20中实现。

以上这些问题就给初学者带来很多的困扰。
在这里插入图片描述

二、迭代器适配器、流迭代器

1、简介

本章将介绍

  • 3种迭代器适配器:分别是反向迭代器适配器、插入型迭代器适配器、移动迭代器适配器。
  • 2种流迭代器:流迭代器流缓冲区迭代器

2、迭代器适配器

迭代器定义方式具体格式
反向迭代器容器类名::reverse_iterator 迭代器名;
插入型迭代器适配器insert_iterator
移动迭代器适配器move_iterator

3、流迭代器

迭代器定义方式具体格式
流迭代器istream_iterator
ostream_iterator
流缓冲区迭代器istreambuf_iterator
ostreambuf_iterator

三、反向迭代器

1、简介

  • 反向迭代器适配器(reverse_iterator),可简称为反向迭代器或逆向迭代器,常用来对容器进行反向遍历,即从容器中存储的最后一个元素开始,一直遍历到第一个元素。

  • 值得一提的是,反向迭代器底层可以选用双向迭代器或者随机访问迭代器作为其基础迭代器。不仅如此,通过对 ++(递增)和 --(递减)运算符进行重载,使得:

    • 当反向迭代器执行 ++ 运算时,底层的基础迭代器实则在执行 – 操作,意味着反向迭代器在反向遍历容器;
    • 当反向迭代器执行 – 运算时,底层的基础迭代器实则在执行 ++ 操作,意味着反向迭代器在正向遍历容器。

在这里插入图片描述

2、模板类

template <class Iterator>
    class reverse_iterator;

注意,Iterator 模板参数指的是模板类中所用的基础迭代器的类型,只能选择双向迭代器或者随机访问迭代器。

这意味着,如果想使用反向迭代器实现逆序遍历容器,则该容器的迭代器类型必须是双向迭代器或者随机访问迭代器。

3、demo

当需要向容器的任意位置插入元素时,就可以使用 insert_iterator 类型的迭代器。

  • 需要说明的是,该类型迭代器的底层实现,需要调用目标容器的 insert() 成员方法。但幸运的是,STL 标准库中所有容器都提供有 insert() 成员方法,因此 insert_iterator 是唯一可用于关联式容器的插入迭代器
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
int main() {
    //创建并初始化一个 vector 容器
    std::vector<int> myvector{ 1,2,3,4,5,6,7,8 };
    //创建并初始化一个反向迭代器
    std::reverse_iterator<std::vector<int>::iterator> my_reiter(myvector.rbegin());//指向 8
    cout << *my_reiter << endl;// 8
    cout << *(my_reiter + 3) << endl;// 5
    cout << *(++my_reiter) << endl;// 7
    cout << my_reiter[4] << endl;// 3
    return 0;
}

输出

8
5
7
3

四、插入迭代器

1、简介

  • 插入迭代器适配器(insert_iterator),简称插入迭代器或者插入器,其功能就是向指定容器中插入元素。值得一提的是,根据插入位置的不同,C++ STL 标准库提供了 3 种插入迭代器,。
迭代器适配器功能
back_insert_iterator在指定容器的尾部插入新元素,但前提必须是提供有 push_back() 成员方法的容器(包括 vector、deque 和 list)。
front_insert_iterator在指定容器的头部插入新元素,但前提必须是提供有 push_front() 成员方法的容器(包括 list、deque 和 forward_list)。
insert_iterator在容器的指定位置之前插入新元素,前提是该容器必须提供有 insert() 成员方法。

接下来我们以insert_iterator为例子讲解下

2、模板类

template< class Container >
class insert_iterator;

3、demo

当需要向容器的任意位置插入元素时,就可以使用 insert_iterator 类型的迭代器。

  • 需要说明的是,该类型迭代器的底层实现,需要调用目标容器的 insert() 成员方法。但幸运的是,STL 标准库中所有容器都提供有 insert() 成员方法,因此 insert_iterator 是唯一可用于关联式容器的插入迭代器
#include <iostream>
#include <iterator>
#include <list>
using namespace std;
int main() {
    //初始化为 {5,5}
    std::list<int> foo(2, 5);
    //定义一个基础迭代器,用于指定要插入新元素的位置
    std::list<int>::iterator it = ++foo.begin();
    //创建一个 insert_iterator 迭代器
    //std::insert_iterator< std::list<int> > insert_it(foo, it);
    std::insert_iterator< std::list<int> > insert_it = inserter(foo, it);
    //向 foo 容器中插入元素
    insert_it = 1;
    insert_it = 2;
    insert_it = 3;
    insert_it = 4;
    //输出 foo 容器存储的元素
    for (std::list<int>::iterator it = foo.begin(); it != foo.end(); ++it)
        std::cout << *it << ' ';
    return 0;
}

输出

5 1 2 3 4 5

五、移动迭代器

1、简介

它是一个迭代器适配器,其行为与底层迭代器完全相同。

2、模板类

template <class Iterator> class move_iterator;

3、demo

#include <iostream>     
#include <iterator>     
#include <vector>       
#include <string>       
#include <algorithm>    
int main () {
   std::vector<std::string> foo (3);
   std::vector<std::string> bar {"sai","ram","krishna"};
   typedef std::vector<std::string>::iterator Iter;
   std::copy ( std::move_iterator<Iter>(bar.begin()),
               std::move_iterator<Iter>(bar.end()),
               foo.begin() );
   bar.clear();
   std::cout << "foo:";
   for (std::string& x : foo) std::cout << ' ' << x;
   std::cout << '\n';
   return 0;
}

输出

foo: sai ram krishna

六、流迭代器

1、简介

  • 它是一个特殊的输入迭代器,可以读取输入流中的连续元素。

2、模板类

template <class T, class charT = char, class traits = char_traits<charT>, 
         class Distance = ptrdiff_t>
   class istream_iterator;

3、demo

#include <iostream>
#include <iterator>
int main () {
   double value1, value2;
   std::cout << "Please insert values: ";
   std::istream_iterator<double> eos;              
   std::istream_iterator<double> iit (std::cin);   
   if (iit!=eos) value1=*iit;
   ++iit;
   if (iit!=eos) value2=*iit;
   std::cout << value1 << "*" << value2 << "=" << (value1*value2) << '\n';
   return 0;
}

输出

Please insert values: 11 11 2
11*11=121

#include <iostream>     
#include <iterator>     
#include <vector>       
#include <algorithm>    
int main () {
   std::vector<int> myvector;
   for (int i = 10; i > 1; i--) myvector.push_back(i*10);
   std::ostream_iterator<int> out_it (std::cout,", ");
   std::copy ( myvector.begin(), myvector.end(), out_it );
   return 0;
}

100, 90, 80, 70, 60, 50, 40, 30, 20,

七、流缓冲区迭代器

1、简介

  • 它是一个特殊的输入迭代器,它从流缓冲区中读取连续的元素。

2、模板类

template <class charT, class traits = char_traits<charT> >
  class istreambuf_iterator;

3、demo

#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>
int main() {
   std::istringstream in("Hello, world");
   std::vector<char> v( (std::istreambuf_iterator<char>(in)),
                         std::istreambuf_iterator<char>() );
   std::cout << "v has " << v.size() << " bytes. ";
   v.push_back('\0');
   std::cout << "it holds \"" << &v[0] << "\"\n";
   std::istringstream s("abc");
   std::istreambuf_iterator<char> i1(s), i2(s);
   std::cout << "i1 returns " << *i1 << '\n'
             << "i2 returns " << *i2 << '\n';
   ++i1;
   std::cout << "after incrementing i1, but not i2\n"
             << "i1 returns " << *i1 << '\n'
             << "i2 returns " << *i2 << '\n';
   ++i2;
   std::cout << "after incrementing i2, but not i1\n"
             << "i1 returns " << *i1 << '\n'
             << "i2 returns " << *i2 << '\n';
}

输出

v has 12 bytes. it holds “Hello, world”
i1 returns a
i2 returns a
after incrementing i1, but not i2
i1 returns b
i2 returns a
after incrementing i2, but not i1
i1 returns b
i2 returns c

参考:
1、C++ STL 容器库 中文文档
2、STL教程:C++ STL快速入门
3、https://www.apiref.com/cpp-zh/cpp/header.html
4、https://en.cppreference.com/w/cpp/container
5、哔哩哔哩——侠姐聊算法——8.2.1 适配器与迭代器
6、WIKI教程_C ++标准库_C++ Library - <iterator>

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

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

相关文章

Mysql列的类型定义(日期和时间类型)

文章目录 前言一、类型表二、类型简介总结 前言 日期与时间类型是为了方便在数据库中存储日期和时间而设计的&#xff0c;数据库有多种表示日期和时间的数据类型。其中&#xff0c;YEAR类型表示年&#xff0c;DATE类型表示日期&#xff0c;TIME类型表示时间&#xff0c;DATETIM…

大模型如何赋能?个人AI助理开始靠谱!

想象一下&#xff0c;生活在这样一个世界里&#xff0c;你有一个个人人工智能助手&#xff0c;它不仅能理解你的需求&#xff0c;还能与你一起学习和成长。一个人工智能无缝融入我们日常生活的世界&#xff0c;使我们能够比以往任何时候都更有效地实现我们的目标。那个世界不再…

Linux磁盘分区扩容

磁盘分区主要包含MBR&#xff08;Master Boot Record&#xff09;和GPT&#xff08;GUID Partition Table&#xff09;两种不同方式&#xff1a; MBR&#xff08;主引导记录&#xff09;&#xff0c;驱动器上的一个特殊的启动扇区&#xff0c;最大支持2TB&#xff0c;最多支持4…

【Redis7】Redis7 主从复制(重点:主从复制原理)

【大家好&#xff0c;我是爱干饭的猿&#xff0c;本文重点介绍Redis7 复制。 后续会继续分享Redis7和其他重要知识点总结&#xff0c;如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下吧】 上一篇文章&#xff1a;《【Redis7】Redis7 事务&管道&…

navicat 远程连接oracle数据库ORA-12170及ORA-28547问题

目录 1.ORA-12170问题 2.ORA-28547 问题 1.ORA-12170问题 这是防火墙端口连接问题&#xff0c;需要在防火墙中设置oracle数据库端口为例外 解决方案 控制面板—windows防火墙—高级设置—入站规则—新建规则 2.ORA-28547 问题 OCI版本不兼容问题&#xff0c;安装的oracle客…

Python每日一练(20230423)

目录 1. 删除链表的倒数第 N 个结点 &#x1f31f;&#x1f31f; 2. 最小覆盖子串 &#x1f31f;&#x1f31f;&#x1f31f; 3. 二叉树的层序遍历 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏…

OpenAI最新官方ChatGPT聊天插件接口《插件安全审查流程》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(六)(附源码)

Plugin review process 插件审查流程 前言Plugin review process 插件审查流程What we are looking for in a plugin 我们正在寻找一个插件Plugin states 插件状态Types of users 用户类型Submit a plugin for review 提交一个插件进行审核其它资料下载 前言 在 ChatGPT 中&am…

【原创】【理论+题型】二次型化标准型 +合同

&#xff08;A&#xff09;二次型化标准型2方法对比 1任何二次型都能化为标准&#xff0c;有正交变换法和配方法 2任何二次型都能通过配方法变为标准型&#xff0c;但不一定能通过正交变化法变 3二次型的规范型唯一&#xff0c;标准型不唯一 4实对称阵的(合同)对角化问题&#…

产品预览 | 系统仿真与三维专业场仿真融合——MWORKS模型降阶工具箱

1 引言 近二十年来&#xff0c;数字化技术迅猛发展&#xff0c;以美国和中国提出装备数字工程为标志&#xff0c;人类迈入全新的数字化时代。装备数字化需要对装备的运行状态和行为进行准确的模拟和预测&#xff0c;这就需要利用系统仿真技术。系统仿真技术能够综合考虑装备的…

Golang每日一练(leetDay0044)

目录 130. 被围绕的区域 Surrounded Regions &#x1f31f;&#x1f31f; 131. 分割回文串 Palindrome Partitioning &#x1f31f;&#x1f31f; 132. 分割回文串 II Palindrome Partitioning II &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专…

启扬方案:瑞芯微3568智慧安防NVR设备解决方案

物联网技术和人工智能技术的发展和应用&#xff0c;让安防行业的视频监控从简单的看见画面到自动识别智能研判&#xff0c;大大地提高视频监控的智能化&#xff0c;提升监控效率。随着智慧城市、智慧交通、智慧社区等项目的实施&#xff0c;面对道路交通、银行、家庭、商场、楼…

App复杂动画实现——Rive保姆级教程 | 京东云技术团队

作者&#xff1a;京东物流 沈明亮 在App开发过程中&#xff0c;如果想实现动画效果&#xff0c;可以粗略分为两种方式。一种是直接用代码编写&#xff0c;像平移、旋转等简单的动画效果&#xff0c;都可以这么干&#xff0c;如果稍微复杂点&#xff0c;就会对开发工程师的数学功…

如何提升电脑使用体验?试试这5款免费软件吧

今天推荐5款实用的开源软件,它们可以极大地提高你的工作和生活效率,让你办公学习的体验更加舒适。 屏幕截图工具——ShareX ShareX是一款免费的开源软件&#xff0c;可以让你快速地捕捉屏幕上的任何区域&#xff0c;并将其保存为图片或视频文件。你还可以使用ShareX来上传你的…

chatgpt智能提效职场办公-ppt怎么做流程图

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 制作PPT流程图的步骤如下&#xff1a; 打开 PowerPoint&#xff0c;选择自己要制作流程图的PPT页面。 在页面中点击“插入”选项卡&am…

gcc编译的过程

文章目录 前言一、gcc 编译四步骤二、gcc编译常用参数三、文件后缀名对应表四、预处理五、编译六、汇编七、链接1、静态链接2、动态链接 前言 GCC 仅仅是一个编译器&#xff0c;没有界面&#xff0c;必须在命令行模式下使用。通过 gcc 命令就可以将源文件编译成可执行文件。 一…

人机识别技术再升级,AIGC为验证码带来万亿种新变化

网上输入关键词“破解验证码”&#xff0c;会出现1740万个搜索结果。“验证码识别、轻松破解、暴力破解、逻辑漏洞破解、简单破解”等等各类关键词的内容&#xff0c;不一而足&#xff0c;关于“如何用破解某某验证码”的帖子更是多如牛毛。 搜索引擎的相关结果 2017年&#xf…

线程池的构造方式

线程池的构造方式 两类构造方式7种实现方法7种线程池的具体使用FixedThreadPoolCachedThreadPoolSingleThreadExecutorScheduledThreadPoolSingleThreadScheduledExecutornewWorkStealingPoolThreadPoolExecutor 说明总结 两类构造方式 在Java语言中&#xff0c;并发编程都是通…

【重新定义matlab强大系列三】MATLAB清洗离群数据(查找、填充或删除离群值)

&#x1f517; 运行环境&#xff1a;matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

异常详解

一、初识异常 异常概念&#xff1a; 所谓异常指的就是程序在 运行时 出现错误时通知调用者的一种机制。 而运行时指的是程序已经编译通过得到 class 文件了, 再由 JVM 执行过程中出现的错误。 1.除以 0 System.out.println(10 / 0); // 执行结果 Exception in thread "…

02 - 学会提问

学会提问 一、引言 1.1 GPT简介 GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种基于Transformer架构的大型预训练语言模型。 凭借其强大的文本生成、理解和处理能力&#xff0c;GPT已在诸如自然语言处理、机器翻译、文本摘要等多个领域取得了显著的…