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

news/2024/9/19 8:08:35/

【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());//指向 8cout << *my_reiter << endl;// 8cout << *(my_reiter + 3) << endl;// 5cout << *(++my_reiter) << endl;// 7cout << my_reiter[4] << endl;// 3return 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.ppmy.cn/news/51290.html

相关文章

威胁行为者针对云中的常见漏洞

Palo Alto Networks 已发布其第 42 单元云威胁报告的第 7 卷。该报告调查了 1300 多家组织。它分析了所有主要云服务提供商 (CSP) 的 210000 个云帐户、订阅和项目中的工作负载&#xff0c;为安全领导者和从业者提供了云安全的多方面视图。 云迁移的速度从 2021 年的 3700 亿…

读取注册表中的REG_QWORD和REG_BINARY(二进制)类型数据

读取注册表中的REG_QWORD和REG_BINARY二进制类型数据 发现的问题注册表中的一些概念&#xff08;统一认识&#xff09;读取代码&#xff08;字节数据大于8的会显示f开头的前缀&#xff09;说明&#xff08;备注&#xff09;改进代码参考链接 发现的问题 首先我们要明确&#x…

无良公司把我从上家挖过来,白嫖了六个月,临近试用期结束才说不合适,催我赶紧找下家!...

职场套路多&#xff0c;一不小心就会掉坑&#xff0c;一位网友讲述了自己的遭遇&#xff1a; 今天被领导催促离职了&#xff0c;当时就是这个领导把他从别的公司挖过来。这家公司催得太急&#xff0c;为了投奔这里&#xff0c;他和上家的HR都闹翻了&#xff0c;上家总监挽留他&…

centos的cd与pwd指令

这里写目录标题 一 切换目录cd&#xff1a;&#xff08;change directory&#xff09;1. cd..2. cd /3. cd -4.绝对路径5.相对路径 二 显示当前目录 pwd(print work directory)三 练习1 查看当前所在目录2 切换到 /usr/local(绝对路径)3 切换到 上一级 /usr4 切换到 /usr/tmp (…

set (集合)数据结构

set(集合)是⼀个⾮常有⽤的数据结构。 它与列表(list)的⾏为类似&#xff0c;区别在于set 不能 包含重复的值。 例如你可能想检查列表中是否包含重复的元素&#xff0c;你有两个选 择&#xff0c;第⼀个需要 使⽤for循环&#xff0c;就像这样&#xff1a; some_list [a, b…

数据结构和算法学习记录——小习题-二叉树的遍历二叉搜索树

目录 二叉树的遍历 1-1 1-2 1-3 二叉搜索树 2-1 2-2 2-3 2-4 答案区 二叉树的遍历 1-1 假定只有四个结点A、B、C、D的二叉树&#xff0c;其前序遍历序列为ABCD&#xff0c;则下面哪个序列是不可能的中序遍历序列&#xff1f; .ABCD .ACDB .DCBA .DABC 1-2 对于…

git从入门到卸载

git是什么&#xff1f; 从git的官网Git可以找到&#xff1a; Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. Git is easy to learn and has a tiny footpr…

第八章 查询和检索:Query DSL

版权声明 本文为Elastic开源社区版权所有,保证独立性和原创性,未获得授权和允许,任何组织和个人不得以任何方式传播或复制或分享。否则必将追究法律责任。 知识内容输出不易,请尊重他人劳动成果。严禁随意传播、复制和盗用他人成果或文章内容用以商业或盈利目的! 1、查询…

紧密联结玩家 | 2023 Google 游戏开发者峰会

玩家的选择是对游戏莫大的认可&#xff0c;重视玩家反馈并和他们建立联系是您的游戏取得成功的关键。我们也在努力创造更多机会&#xff0c;让您的游戏从琳琅满目的列表中脱颖而出&#xff0c;帮助您吸引更多用户。 上篇内容我们介绍了帮助您优化游戏性能的几大功能更新&#x…

扬声器,打印机2键触摸VK3602K SOP8 2键2通道触摸检测芯片技术资料直接输出自动校准功能

型号&#xff1a;VK3602K 封装形式&#xff1a;SOP8 KPP2620 VK3602K具有2个触摸按键&#xff0c;可用来检测外部触摸按键上人手的触摸动作。该芯片具有较高的集成度&#xff0c;仅需极少的外部组件便可实现触摸按键的检测。 提供了2路直接输出功能,可通过IO脚选择输出电平。…

Virtual Private Network

目录 一&#xff1a;VPN问答 二&#xff1a;实验 一&#xff1a;VPN问答 1.什么是数据认证&#xff0c;有什么作用&#xff0c;有哪些实现的技术手段? 数据认证是指通过一系列验证过程检查数据的完整性、真实性、可靠性和准确性&#xff0c;以确保这些数据来自于已知或可信…

Elasticsearch painless脚本教程(包含Java API和SpringDataElasticsearch调用脚本)

Elasticsearch painless脚本 1.什么是painless2.painless的特性3.使用kibana进行准备操作3.1 使用kibana创建索引和映射3.2 使用kibana添加测试数据 4.使用painless执行查询操作关于脚本查询须知4.1 字段查询脚本4.1 排序查询脚本 5.如何使用painless执行更新操作关于脚本查询须…

分布式多级缓存

caffeine 基础使用 三种缓存驱逐机制 lua语言 lua的基础数据类型 字符串拼接使用.. 循环 函数 条件控制

菜鸟教程,前端部分测验

html 测验一 问题 HTML 指的是&#xff1f; 超文本标记语言&#xff08;Hyper Text Markup Language&#xff09; 家庭工具标记语言&#xff08;Home Tool Markup Language&#xff09; 超链接和文本标记语言&#xff08;Hyperlinks and Text Markup Language&#xff09; 正…

如何利用TURF分析来对餐厅菜品进行组合搭配?

1.数据源说明 1.1 数据简单说明 本数据源采用的是某餐厅8月份的销售明细表。本文会主要用到一下字段值&#xff1a; order_id&#xff0c; 产品订单号dishes_name&#xff0c;菜品名称counts, 消费数量amounts&#xff0c;消费金额 1.2 数据截图 以下是数据源的截图 1.3…

xcode历史版本下载

一、背景 较早之前做过一个项目&#xff0c;当时使用swift 3.x开发。 项目结束后就没再有新需求与更新。 但最近呢需要对项目的某些功能进行调整&#xff0c;项目又重新被拾了起来。 我们知道现在的swift 版本已经到了 5.x&#xff0c; 相应的语法上较 3.x版本也有了不小的变化…

java-集合面试题

目录 Java常见的集合类对ArrayList的理解对LinkedList的理解ArrayList与LinkedList的区别如何解决ArrayList和LinkedList的线程安全问题如何实现数组和List之间的转换HashMap实现原理put方法执行流程HashMap的寻址算法HashMap扩容机制为何HashMap的数组长度一定是2的整次幂Hash…

WPF常用的布局方式

WPF&#xff08;Windows Presentation Foundation&#xff09;是一个用于创建 Windows 桌面应用程序的 UI 框架。在 WPF 中&#xff0c;有多种布局方式可供使用&#xff0c;以下是一些常用的布局方式及其示例&#xff1a; 栅格布局&#xff08;Grid&#xff09;&#xff1a;栅…

自动驾驶落地如何降本?这家头部公司有自己的独特之处

一直以来&#xff0c;商用车智能化与乘用车有很多差异化&#xff0c;比如&#xff0c;B端客户对于规模车队的采购成本&#xff0c;智能化应用场景的适配性以及对自动驾驶更为务实的认知。 4月18日&#xff0c;2023上海车展&#xff0c;作为场景化新能源的自动驾驶全球领导者&am…

【Android入门到项目实战-- 7.1】—— 如何使用通知?

目录 一、创建通知的步骤 1、创建一个NotificationManager实例 2、使用一个Builder构造器来创建Notification对象 3、设置标题、文字、时间和图标等信息 4、显示通知 二、通知实例演示 三、实现通知的点击效果 1、PendingIntent 什么是PendingIntent&#xff1f; 如何使…