重温设计模式--C++迭代器种类和用法

devtools/2024/12/26 14:22:28/

文章目录

      • 定义
      • 1、 输入迭代器(Input Iterator
      • 2、输出迭代器(Output Iterator)
      • 3、前向迭代器(Forward Iterator)
      • 4、双向迭代器(Bidirectional Iterator)
      • 5、 随机访问迭代器(Random - Access Iterator)

定义

它提供了一种方法来顺序访问一个聚合对象(如数组、列表、树等各种容器类型的数据结构)中的各个元素,而又无需暴露该聚合对象的内部表示

1、 输入迭代器(Input Iterator

  • 定义和特点
    • 输入迭代器是一种只读迭代器,它能够从一个序列中读取元素,并且只能单向向前移动。其主要目的是用于支持对容器元素的顺序读取操作,就像从一个输入流(如std::istream)中读取数据一样。
    • 它支持的操作包括解引用(*操作符)以获取当前元素的值、++操作符来将迭代器移动到下一个元素位置,并且可以通过==!=操作符来比较两个迭代器是否指向相同的位置。但是,一旦迭代器向前移动,就不能再回到之前的位置。
  • 应用场景
    • 适用于单次遍历容器元素的场景,比如在从标准输入读取数据并存入容器后,使用输入迭代器来逐个读取容器中的数据进行处理,且不需要修改数据,也不需要多次遍历。例如,将std::cin读取的整数序列存入std::vector后,使用输入迭代器来计算这些整数的和。
  • 示例代码片段
    • 以下是一个简单的示例,使用std::istream_iterator(这是C++标准库中基于输入迭代器概念实现的迭代器类型)从std::cin读取整数,并存入std::vector,然后再使用输入迭代器遍历vector并输出整数。
    #include <iostream>
    #include <vector>
    #include <iterator>
    int main() {std::vector<int> numbers;std::istream_iterator<int> inputIt(std::cin), endIt;while (inputIt!= endIt) {numbers.push_back(*inputIt);++inputIt;}std::istream_iterator<int> outputIt(numbers.begin());while (outputIt!= numbers.end()) {std::cout << *outputIt << " ";++outputIt;}std::cout << std::endl;return 0;
    }
    

2、输出迭代器(Output Iterator)

  • 定义和特点
    • 输出迭代器主要用于向容器或其他输出目标写入数据,同样是单向的,不过它侧重于数据的输出操作。与输入迭代器类似,它也支持++操作符来移动位置,并且可以通过解引用操作符*来将数据写入到当前位置,但解引用操作主要用于赋值,而不是获取值。
  • 应用场景
    • 常用于将数据写入容器的场景,例如将一个计算结果序列逐个存入容器中。在对容器进行填充新元素的操作,特别是从其他数据源生成数据并填充到容器时,输出迭代器很有用。
  • 示例代码片段
    • 以下示例使用std::ostream_iterator(C++标准库中的输出迭代器类型)将一个整数序列输出到std::cout,它将数据从容器(这里是vector)中逐个取出并输出到控制台。
    #include <iostream>
    #include <vector>
    #include <iterator>
    int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};std::ostream_iterator<int> outputIt(std::cout, " ");for (int num : numbers) {*outputIt = num;++outputIt;}std::cout << std::endl;return 0;
    }
    

3、前向迭代器(Forward Iterator)

  • 定义和特点
    • 前向迭代器在输入迭代器和输出迭代器的基础上提供了更多的功能,它不仅可以单向向前移动,而且可以多次遍历同一个序列。它支持所有输入迭代器和输出迭代器的操作,同时解引用操作更加灵活,既可以读取也可以修改元素的值。
  • 应用场景
    • 在需要对容器元素进行多次读取和修改操作的场景中很有用。例如,在一个算法中,可能需要多次遍历一个容器来更新元素的值,或者在一个容器中查找满足特定条件的元素,然后对这些元素进行修改。
  • 示例代码片段
    • 以下是一个简单的示例,使用自定义的前向迭代器(假设已经有一个自定义的容器类和对应的前向迭代器类实现)来遍历容器并将每个元素的值加倍。
    class MyForwardIterator;
    class MyContainer {
    public:MyForwardIterator begin();MyForwardIterator end();// 其他容器相关的操作
    };
    class MyForwardIterator {
    public:MyForwardIterator& operator++();int& operator*();bool operator==(const MyForwardIterator& other) const;bool operator!=(const MyForwardIterator& other) const;// 其他迭代器相关的操作
    };
    void doubleElements(MyContainer& container) {MyForwardIterator it = container.begin();MyForwardIterator endIt = container.end();while (it!= endIt) {*it *= 2;++it;}
    }
    

4、双向迭代器(Bidirectional Iterator)

  • 定义和特点
    • 双向迭代器在继承前向迭代器功能的基础上,增加了向后移动的能力。它可以通过--操作符将迭代器向反方向移动,从而能够更加灵活地在容器元素之间进行遍历。双向迭代器支持所有前向迭代器的操作,同时还支持反向移动操作。
  • 应用场景
    • 在需要在容器中双向移动的场景中非常有用。例如,在处理双向链表这种数据结构时,或者在一个算法中需要根据某些条件来回遍历容器元素的情况,如在一个排序算法中,可能需要先正向遍历找到一个合适的位置,然后再反向遍历来调整元素的顺序。
  • 示例代码片段
    • std::list为例,std::list的迭代器是双向迭代器。以下代码展示了如何使用双向迭代器在std::list中双向移动并操作元素。
    #include <iostream>
    #include <list>
    int main() {std::list<int> numbers = {1, 2, 3, 4, 5};std::list<int>::iterator it = numbers.begin();// 正向遍历并输出while (it!= numbers.end()) {std::cout << *it << " ";++it;}std::cout << std::endl;it = numbers.end();--it;// 反向遍历并输出while (it!= numbers.begin()) {std::cout << *it << " ";--it;}std::cout << *it << std::endl;return 0;
    }
    

5、 随机访问迭代器(Random - Access Iterator)

  • 定义和特点
    • 随机访问迭代器是功能最强大的一种迭代器类型,它除了支持双向迭代器的所有操作外,还支持通过索引(类似数组下标)的方式直接访问容器中的任意元素。可以使用[]操作符进行随机访问,还可以进行迭代器之间的算术运算,如+-+=-=等操作,来快速地在容器元素之间进行跳转。
  • 应用场景
    • 在需要高效地访问容器中任意位置元素的场景中非常有用。例如,在对数组或者std::vector这种支持随机访问的数据结构进行快速排序、二分查找等算法时,随机访问迭代器能够大大提高算法的效率,因为可以直接定位到需要操作的元素位置,而不需要逐个移动迭代器来访问。
  • 示例代码片段
    • 以下以std::vector为例,展示随机访问迭代器的使用。
    #include <iostream>
    #include <vector>
    int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};std::vector<int>::iterator it = numbers.begin();// 通过随机访问迭代器直接访问第三个元素(索引为2)std::cout << numbers[2] << std::endl;// 使用算术运算移动迭代器it += 3;std::cout << *it << std::endl;return 0;
    }
    
  1. 不是所有的STL迭代器都是随机访问迭代器
    • STL(标准模板库)中有多种容器,每种容器所提供的迭代器类型不同,以适应其内部数据结构的特性和访问需求。
    • 输入迭代器(Input Iterator)和输出迭代器(Output Iterator)相关容器
      • 在一些基于流的操作或者单次单向数据读取/写入场景下会涉及到这两类迭代器相关的概念。例如,istream_iteratorostream_iterator分别是输入迭代器和输出迭代器类型。它们主要用于从输入流(如std::cin)读取数据到容器或者将容器中的数据输出到输出流(如std::cout),这种迭代器不支持随机访问,而是单向的读取或写入操作。
    • 前向迭代器(Forward Iterator)相关容器
      • forward_list(单向链表)是一个典型的提供前向迭代器的容器。前向迭代器可以单向向前移动,并且可以多次遍历序列,但不支持像随机访问迭代器那样通过索引直接访问元素或者进行迭代器的算术运算。例如,对于std::forward_list<int> flist;,其迭代器只能使用++操作符向前移动来遍历链表中的元素。
    • 双向迭代器(Bidirectional Iterator)相关容器
      • list(双向链表)和setmultisetmapmultimap(关联容器)等提供的是双向迭代器。以std::list为例,它的迭代器可以向前和向后移动,通过--操作符实现反向遍历,但是也不支持像随机访问迭代器一样的索引访问方式。例如,对于std::list<int> myList;,可以使用myList.begin()myList.end()获取双向迭代器,然后在列表元素之间双向移动,但不能像在vector中那样使用[]操作符直接访问元素。
  2. 部分STL容器提供随机访问迭代器
    • vectordeque容器
      • vector(动态数组)和deque(双端队列)是STL中提供随机访问迭代器的典型容器。它们内部的数据结构允许通过索引直接访问元素,就像访问数组元素一样。例如,对于std::vector<int> vec;,可以使用vec[3]来直接访问索引为3的元素,也可以通过迭代器进行算术运算,如vec.begin() + 5来获取指向第6个元素(索引为5)的迭代器。这种随机访问的特性使得vectordeque在很多需要高效访问元素的算法中表现出色,比如快速排序、二分查找等算法可以充分利用这种随机访问迭代器的优势来提高效率。
    • array容器
      • array是一个固定大小的数组容器,它也提供随机访问迭代器。由于其大小在编译时就已经确定,和普通数组类似,它支持通过索引直接访问元素,其迭代器也具备随机访问的能力,如std::array<int, 5> arr;,可以使用arr[2]访问元素,也可以利用随机访问迭代器进行其他操作。

http://www.ppmy.cn/devtools/145546.html

相关文章

基于python语音启动电脑应用程序

osk模型进行输入语音转换 txt字典导航程序路径 pyttsx3引擎进行语音打印输出 关键词程序路径 import os import json import queue import sounddevice as sd from vosk import Model, KaldiRecognizer import subprocess import time import pyttsx3 import threading# 初始…

【YashanDB知识库】XMLAGG方法的兼容

本文内容来自YashanDB官网&#xff0c;原文内容请见 https://www.yashandb.com/newsinfo/7802943.html?templateId1718516 【关键字】 XMLAGG方法的兼容 【问题描述】 崖山数据库不支持将XMLAGG相关的函数内容&#xff0c;需要替换成支持的功能函数WM_CONCAT(T.COLUMN_NAME…

nlohmann的常用用法

3.9之后新增了 2个宏 可以实现 结构体和json的快速转换 1.结构体序列化json 1.1 3.9 #include <iostream> #include <string> #include <vector> #include "json.hpp"// 定义用户结构体 struct User {std::string name; // 用…

YOLO11改进-注意力-引入多尺度卷积注意力模块MSCAM

如何在增强特征图的同时降低计算成本&#xff0c;以提升模型性能。基于此&#xff0c;MSCAM 模块采用了多尺度卷积注意力机制&#xff0c;通过 CAB、SAB 和 MSCB 三个子模块协同工作。CAB 利用自适应池化和卷积操作生成通道注意力权重&#xff0c;强调重要通道特征&#xff1b;…

修改输出资源的名称和路径、自动清空上次打包资源

一、修改输出资源的名称和路径 1.1 配置 const path require("path");module.exports {// 入口【相对路径】entry: ./src/main.js,// 输出output: {// 文件的输出路径【绝对路径】// __dirname 当前文件的文件夹的绝对路径path: path.resolve(__dirname, dist),/…

Android 之 List 简述

一、简单创建方式 Android 开发中&#xff0c;列表有很多种类&#xff0c;如ArrayList、LinkedList、List、MutableList等&#xff0c;创建列表的方式如下所示&#xff1a; fun listDemo() {// 使用 listOf 创建不可变的空列表val list listOf<Int>()val list1 listOf…

常用的消息中间件都有哪些

在Java编程领域&#xff0c;消息中间件扮演着举足轻重的角色&#xff0c;它们为分布式系统提供了高效、可靠的异步通信机制。 1. RabbitMQ&#xff1a; • 这是一个源自AMQP&#xff08;高级消息队列协议&#xff09;的消息中间件。 • 它提供了丰富的消息路由、过滤和持久化功…

安卓project级别build.gradle和主module的build.gradle

以穿山甲为例讲解 如下图 gradle和gradle插件对应关系 Android Gradle 插件 8.7 版本说明 | Android Studio | Android Developers gradle对应在项目里的配置为 gradle插件对应的位置为