38 C++ STL模板库7-迭代器

C++ STL模板库7-迭代器

文章目录

  • C++ STL模板库7-迭代器
    • 一、迭代器的核心作用
    • 二、迭代器的五大分类与操作
    • 三、关键用法与代码示例
      • 1. 迭代器的原理
      • 2. 迭代器用法与示例
      • 3. 迭代工具用法示例
      • 4. 使用技巧

迭代器是C++中连接容器与算法的通用接口,提供了一种访问容器元素的统一方式,类似于指针但更强大。
使用迭代器需包含 <iterator>

一、迭代器的核心作用

  1. 解耦容器与算法

    • 算法(如 std::sort, std::copy)通过迭代器操作容器,无需知道容器具体类型(数组、链表等)。
    • 示例:std::sort(vec.begin(), vec.end()) 可对 vectordeque 等均生效。
  2. 统一访问模式

    • 无论容器如何存储数据(连续内存/链表/树),迭代器提供一致的遍历接口(++, *, ->)。
  3. 支持范围操作

    • 通过 begin()end() 定义半开区间 [begin, end),安全遍历且避免越界。

二、迭代器的五大分类与操作

  1. 根据功能由弱到强分为:

    分类支持操作典型容器
    输入迭代器只读一次(*it, ++, ==istream_iterator
    输出迭代器只写一次(*it=, ++ostream_iterator
    前向迭代器多次读写(++forward_list, 哈希表
    双向迭代器双向移动(++, --list, set, map
    随机访问迭代器跳跃访问(+n, -n, [], 比较)vector, deque, 数组
  2. 核心声明语法

    容器类型::iterator 变量名;         // 可修改元素的迭代器  
    容器类型::const_iterator 变量名;   // 只读元素的迭代器  
    容器类型::reverse_iterator 变量名; // 反向迭代器  
    
    vector<int>::iterator it = vn.begin ();
    array<int,5>::iterator it = vn.begin ();
    array<string>::iterator it = vn.begin ();
    

    下面的语句令一个整型向量的迭代器指向该向量的第一个元素:
    it = vn.begin ();
    而下面的语句令该迭代器指向向量中最后一个元素的下一个位置:
    it = vn.end ();
    通过begin()和end()构建迭代循环:

    for (vector<int>::iterator it = vn.begin(); it != vn.end (); it++)...
    一般用 auto 类型推导代替 vector<int>::iterator ,来缩短代码和防止出错
    

    遍历容器中元素。
    迭代器的基本操作:*、++/–、+/-/+=/-=整数(部分容器的迭代器)

  3. 迭代器工具函数(需包含 <iterator>

    函数语法/示例作用
    std::advanceadvance(iter, n)移动迭代器n步(支持正负方向)
    std::distancedistance(iter1, iter2)计算两个迭代器之间的元素数量
    std::next/std::prevnext(iter, n=1)prev(iter, n=1)获取移动后的迭代器副本(不修改原迭代器)

    示例:

    std::deque<int> dq = {10, 20, 30};  
    auto dq_it = dq.begin();  
    std::advance(dq_it, 2);      // 移动到第3个元素(30)  
    auto count = std::distance(dq.begin(), dq.end()); // 计算长度(3)  
    auto next_it = std::next(dq_it, -1); // 获取前一个位置的迭代器(20)  
    

三、关键用法与代码示例

1. 迭代器的原理

迭代器本质是抽象化的指针
迭代器模式的核心价值在于解耦数据结构和算法

int arr[5] = {10, 20, 30, 40, 50};  // ✅ 指针作为迭代器的用法  
int* begin = arr;      // 首元素迭代器  
int* end = arr + 5;    // 尾后迭代器  // 遍历操作  
for (int* it = begin; it != end; ++it) {  std::cout << *it << " ";  // 输出:10 20 30 40 50  
}  // 随机访问  
*(begin + 2) = 99;    // 修改第三个元素 → arr[2]=99  
std::cout << begin[3]; // 输出:40(等价于*(begin+3))  // 算法应用  
auto min_pos = begin;  
for (int* p = begin + 1; p != end; ++p) {  if (*p < *min_pos) min_pos = p;  
}  
std::cout << "最小值:" << *min_pos; // 输出:10    
  • 指针迭代的缺点:
    1. 无边界检查:end + 1 会导致未定义行为
    2. 无类型封装:无法区分 int* 是迭代器还是普通指针
    3. 功能缺失:不支持反向迭代器等高级特性

2. 迭代器用法与示例

  1. 遍历数组(正/反向)

    #include <iostream>  
    #include <array>  int main() {  std::array<int, 4> arr = {10, 20, 30, 40};  // 正向迭代器(常量与非常量)  for(auto it = arr.begin(); it != arr.end(); ++it) {  *it += 1;  // 修改元素值  std::cout << *it << " ";  // 输出:11 21 31 41  }  // 反向迭代器(C++11)  for(auto rit = arr.rbegin(); rit != arr.rend(); ++rit) {  std::cout << *rit << " ";  // 输出:41 31 21 11  }  
    }  
    
  2. 遍历容器

    std::array<int, 3> arr = {10, 20, 30};  for (std::array<int, 3>::iterator it = arr.begin();  it != arr.end();  ++it) {  std::cout << *it << " "; // 输出:10 20 30  
    }  auto it = arr.begin() + 2;  
    *it = 99;                //  // C++11范围for(底层使用迭代器)  
    for (int val : arr) {  std::cout << val << " ";  //输出:10 20 99  
    }   
    
  3. 与标准算法结合

    #include <iostream>  
    #include <array>  
    #include <algorithm>  
    #include <numeric>  //  accumulate✅ 必须包含此头文件  int main() {  std::array<int, 4> arr = {10, 20, 30, 40};  // 正向迭代器(常量与非常量)//std::array<int, 4>::iterator it for(auto it = arr.begin();  it != arr.end();  ++it) {  *it += 1;  // 修改元素值  std::cout << *it << " ";  // 输出:11 21 31 41  }  // 反向迭代器(C++11)  for(auto rit = arr.rbegin();  rit != arr.rend();  ++rit) {  std::cout << *rit << " ";  // 输出:41 31 21 11  }  std::sort(arr.begin(), arr.end());  // 查找元素  auto pos = std::find(arr.cbegin(), arr.cend(), 21);  if(pos != arr.end()) {  std::cout << "位置索引:" << pos - arr.begin()<<std::endl;  // 输出:1  }  // 累加计算(C++17)  int sum = std::accumulate(arr.cbegin(),  arr.cend(), 0);std::cout << "总和:" << sum<<std::endl;  // 输出:104 
    }
    
  4. 随机访问操作

    auto first = arr.begin();  
    auto third = first + 2;  // 直接跳转到索引2  std::cout << *(first + 1) <<std::endl;    // 输出:21(等价于arr[1])  
    std::cout << (third > first) <<std::endl; // 输出:1(支持比较)  
    std::cout << third[1] <<std::endl;        // 输出:41(索引相对访问)  
    
  5. 安全访问:常量迭代器

    void printArray(const std::array<int, 4>& arr) 
    {  // 使用cbegin/cend防止意外修改  for(auto it = arr.cbegin(); it != arr.cend(); ++it) {  std::cout << *it << " ";  // *it = 0;  // 错误!常量迭代器禁止修改  }  
    }
    

3. 迭代工具用法示例

  1. 基础迭代器操作工具

    1. std::next / std::prev(安全位移)

      #include <iterator>
      std::vector<int> vec{10, 20, 30, 40};// 向前移动2步(支持所有迭代器类型)
      auto it_next = std::next(vec.begin(), 2); // 指向30 // 向后移动1步(仅双向迭代器可用)
      auto it_prev = std::prev(vec.end(), 1);   // 指向40 
      
    2. std::advance(原位修改迭代器)

      auto it = vec.begin();
      std::advance(it, 3);  // it直接指向40(无返回值,修改原迭代器)
      

      特性对比:

      • std::next的区别:直接修改迭代器,适用于循环中逐步推进。
    3. std::distance(计算距离)

      int len = std::distance(vec.begin(), vec.end()); // 输出4(元素总数)
      

      兼容性:

      • 随机访问迭代器:O(1) 时间复杂度
      • 其他迭代器:O(n) 时间复杂度(需遍历)

4. 使用技巧

  • 迭代器的显式声明和类型推导

    • 显式声明
      std::array<int, 4>::iterator it;
    • 类型推导
      auto it;
  • 获取首尾元素的迭代器

    auto front_it = arr.begin();      // 首元素迭代器  
    auto back_it  = arr.end() - 1;     // 尾元素迭代器(因end()指向末尾后一位)  
    
  • 数组与指针互操作

    int* ptr = arr.data();           // 获取原生指针  
    auto it_from_ptr = arr.begin() + (ptr - arr.data()); // 指针转迭代器  
    
  • 优先使用范围for循环

    for (int val : arr) { ... }  // 简洁安全  
    
  • 只读访问用cbegin/cend

    auto it = arr.cbegin();  // 明确表达只读意图  
    
  • 随机访问时检查边界

    if(index < arr.size()) {  auto it = arr.begin() + index;  
    }  
    

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

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

相关文章

【0基础3ds Max】学习计划

3ds Max 作为一款功能强大的专业 3D 计算机图形软件&#xff0c;在影视动画、游戏开发、建筑可视化、产品设计和工业设计等众多领域有着广泛的应用。 目录前言一、第一阶段&#xff1a;基础认知&#xff08;第 1 - 2 周&#xff09;​二、第二阶段&#xff1a;建模技术学习&…

用 Enigma Virtual Box 将 Qt 程序打包成单 exe

上一篇介绍了用windeployqt生成可运行的多文件程序,但一堆文件分发起来不够方便。有没有办法将所有文件合并成一个 exe? 答案是肯定的 用Enigma Virtual Box工具就能实现。本文就来讲解如何用它将 Qt 多文件程序打包为单一 exe,让分发更轻松。 其中的 一定要选 第二个 一…

【LeetCode 热题 100】45. 跳跃游戏 II

Problem: 45. 跳跃游戏 II 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说&#xff0c;如果你在索引 i 处&#xff0c;你可以跳转到任意 (i j) 处&#xff1a; 0 < j < nums[i] 且 i j &…

池式管理之线程池

1.初识线程池问&#xff1a;线程池是什么&#xff1f;答&#xff1a;维持管理一定数量的线程的池式结构。&#xff08;维持&#xff1a;线程复用 。 管理&#xff1a;没有收到任务的线程处于阻塞休眠状态不参与cpu调度 。一定数量&#xff1a;数量太多的线程会给操作系统带来线…

婴儿 3D 安睡系统专利拆解:搭扣与智能系带的锁定机制及松紧调节原理

凌晨2点&#xff0c;你盯着婴儿床里的小肉团直叹气。刚用襁褓裹成小粽子才哄睡的宝宝&#xff0c;才半小时就蹬开了裹布&#xff0c;小胳膊支棱得像只小考拉&#xff1b;你手忙脚乱想重新裹紧&#xff0c;结果越裹越松&#xff0c;裹布滑到脖子边&#xff0c;宝宝突然一个翻身&…

pandas中df.to _dict(orient=‘records‘)方法的作用和场景说明

df.to _dict(orientrecords) 是 Pandas DataFrame 的一个方法&#xff0c;用于将数据转换为字典列表格式。以下是详细解释及实例说明&#xff1a; 一、核心含义作用 将 DataFrame 的每一行转换为一个字典&#xff0c;所有字典组成一个列表。 每个字典的键&#xff08;key&#…

阿里云Anolis OS 8.6的公有云仓库源配置步骤

文章目录一、备份现有仓库配置&#xff08;防止误操作&#xff09;二、配置阿里云镜像源2.1 修改 BaseOS 仓库2.2 修改 AppStream 仓库三、清理并重建缓存四、验证配置4.1 ​检查仓库状态​&#xff1a;五、常见问题解决5.1 ​HTTP 404 错误5.2 ​网络连接问题附&#xff1a;其…

回归预测 | Matlab实现CNN-BiLSTM-self-Attention多变量回归预测

回归预测 | Matlab实现CNN-BiLSTM-self-Attention多变量回归预测 目录回归预测 | Matlab实现CNN-BiLSTM-self-Attention多变量回归预测预测效果基本介绍程序设计参考资料预测效果 基本介绍 1.Matlab实现CNN-BiLSTM融合自注意力机制多变量回归预测&#xff0c;CNN-BiLSTM-self-…

103、【OS】【Nuttx】【周边】文档构建渲染:Sphinx 配置文件

【声明】本博客所有内容均为个人业余时间创作&#xff0c;所述技术案例均来自公开开源项目&#xff08;如Github&#xff0c;Apache基金会&#xff09;&#xff0c;不涉及任何企业机密或未公开技术&#xff0c;如有侵权请联系删除 背景 接之前 blog 【OS】【Nuttx】【周边】文…

转换一个python项目到moonbit,碰到报错输出:编译器对workflow.mbt文件中的类方法要求不一致的类型注解,导致无法正常编译

先上结论&#xff1a;现在是moon test的时候有很多报错&#xff0c;消不掉。问题在Trae中用GLM-4.5模型&#xff0c;转换一个python项目到moonbit&#xff0c;碰到报错输出&#xff1a;报错输出经过多次尝试修复&#xff0c;我发现这是一个MoonBit编译器的bug。编译器对workflo…

【C#补全计划】事件

一、事件的概念1. 事件是基于委托的存在&#xff0c;是委托的安全包裹&#xff0c;让委托的使用更具有安全性2. 事件是一种特殊的变量类型二、事件的使用1. 语法&#xff1a;event 委托类型 事件名;2. 使用&#xff1a;&#xff08;1&#xff09;事件是作为成员变量存在与类中&…

java内存缓存

我们在项目中会经常使Redis和Memcache,但是简单项目就没必要使用专门的缓存框架来增加系统的复杂性。用Java代码逻辑就能实现内存级别的缓存。1.定时任务线程池使用ScheduledExecutorService结合ConcurrentHashMap&#xff0c;如果你使用的是ConcurrentHashMap&#xff0c;你可…

智能工厂生产监控大屏-vue纯前端静态页面练习

学习前端还是非常有意思的&#xff0c;因为前端真的是可见即所得&#xff0c;可以做出来非常好看漂亮的页面&#xff0c;最近我就在使用前端技术 做一些大屏报表&#xff0c;在制作这些大屏报表过程中&#xff0c;又熟练的练习了自己的学到的相关的前端技术&#xff0c;接下来把…

HTTP 协议详细介绍

目录一、HTTP 的基本概念与历史演进1. 核心定义2. 历史版本演进二、HTTP 的核心工作原理1. 请求-响应模型2. 基于 TCP 的传输&#xff08;HTTP/1.1、HTTP/2&#xff09;三、HTTP 请求结构1. 请求行2. 请求头3. 请求体四、HTTP 响应结构1. 状态行2. 响应头3. 响应体五、HTTP 与 …

正则化:从过拟合到泛化的「平衡艺术」

在机器学习领域&#xff0c;有一个几乎所有从业者都会遇到的「噩梦」&#xff1a;模型在训练集上表现完美&#xff08;损失趋近于0&#xff09;&#xff0c;但在测试集上却大幅「翻车」。这种现象被称为「过拟合」&#xff08;Overfitting&#xff09;&#xff0c;它像一把双刃…

[Python 基础课程]根据描述定义一个 Person 类

人都属于人类这个物种&#xff0c;每一个人都会有姓名和年龄&#xff0c;人都可以介绍自己&#xff0c;随着时间的流逝&#xff0c;人都会增加年龄&#xff0c;每一个人都能获取到自己的物种信息。 我们的抽象过程&#xff1a; 所有的 Person 对象都应该有一个共同的属性来表示…

热门手机机型重启速度对比

以下是2023-2024年市场主流热门手机机型的重启速度对比分析&#xff0c;基于公开测试数据和用户反馈整理&#xff08;数据会因系统版本和测试环境不同存在波动&#xff09;&#xff1a;旗舰机型重启速度排名&#xff08;冷启动&#xff09;排名机型平均重启时间关键配置优化技术…

第454题.四数相加II

第454题.四数相加II 力扣题目链接(opens new window) 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) &#xff0c;使得 A[i] B[j] C[k] D[l] 0。 为了使问题简单化&#xff0c;所有的 A, B, C, D 具有相同的长度 N&#xff0c;且 0 ≤ N ≤…

力扣top100(day04-05)--堆

本文为力扣TOP100刷题笔记 笔者根据数据结构理论加上最近刷题整理了一套 数据结构理论加常用方法以下为该文章&#xff1a; 力扣外传之数据结构&#xff08;一篇文章搞定数据结构&#xff09; 215. 数组中的第K个最大元素 class Solution {// 快速选择递归函数int quickselect(…

CCS双轴相位偏移光源 让浅凹痕无处遁形

在工业检测中&#xff0c;浅凹痕表面检测对精度和可靠性要求极高&#xff0c;工业光源在此过程中扮演着关键角色&#xff0c;工业光源通过精准的光学设计&#xff08;角度、波长、强度&#xff09;将肉眼不可见的浅凹痕转化为可量化的光学信号&#xff0c;是实现高精度自动化检…