《C++ Primer》第10章 算法(二)

参考资料:

  • 《C++ Primer》第5版
  • 《C++ Primer 习题集》第5版

10.4 再探迭代器(P357)

除了为每个容器定义的迭代器外,头文件 iterator 中还定义了额外的几种迭代器:

  • 插入迭代器(insert iterator):这些迭代器被绑定到一个容器上,可以向容器中插入元素
  • 流迭代器(stream iterator):这些迭代器被当顶到输入或输出流上,可用来遍历所关联的 IO 流。
  • 反向迭代器(reverse iterator):除 forward_list 外的所有标准库容器都有反向迭代器。
  • 移动迭代器(move iterator):用于移动元素的迭代器。

10.4.1 插入迭代器(P358)

插入器是一种迭代器适配器,接受一个容器,生成一个迭代器,能实现向容器中插入元素:

9c85b4e5133a340d1339db1dfc539a8

插入迭代器有三种类型,区别在于插入元素的位置:

  • back_inserter :使用 push_back
  • front_inserter :使用 push_front
  • inserter :使用 insert ,第二个参数为指向给定容器的迭代器。
vector<int> vi = { 0,1,2,3 };
list<int> v1, v2;
// 注意体会inserter和front_inserter的区别
auto it1 = inserter(v1, v1.begin());
auto it2 = front_inserter(v2);
for (auto i : vi) it1 = i, it2 = i;
for (auto i : v1) cout << i << ' ';    // 输出0 1 2 3
cout << endl;
for (auto i : v2) cout << i << ' ';    // 输出3 2 1 0

10.4.2 iostream迭代器(P359)

这部分不是很懂

流迭代器将对应的流当作一个特定类型元素的序列。创建一个流迭代器时,必须指定迭代器要读写的类型。

istream_iterator操作

a1ce62b884ddad959dfa85308164973

istream_iterator 通过 >> 来读取流,所以其要读取的数据类型必须定义了 >> 运算符:

istream_iterator<int> int_it(cin);    // 从cin读取int
istream_iterator<int> eof;    // 定义尾后迭代器
// 
vector<int> vi(int_it, eof);

使用算法操作流迭代器

istream_iterator<int> in(cin), eof;
cout << accumulate(in, eof, 0) << endl;

istream_iterator允许懒惰求值

当我们将一个 istream_iterator 绑定到一个流时,标准库不保证迭代器立即从流读取数据,具体实现可以知道我们使用迭代器时才读取读取数据。

ostream_iterator操作

94139cc852820f4982a9b3f21ef7c92

我们可以对具有 << 的类型定义 ostream_iterator 。在创建 ostream_iterator 时,我们可以提供第二个参数,类型为 C 风格字符串,在输出每个元素后都会打印此字符串。必须ostream_iterator 绑定到一个流。

此处应有图片

vector<int> vi = { 1,2,3,4,5 };
ostream_iterator<int> out(cout, ", ");
for (auto i : vi) {*out++ = i;
}
cout<<endl;
// 输出:1, 2, 3, 4, 5,

简单写法:

copy(vi.begin(), vei.end(), out);
cout<<endl;

10.4.3 反向迭代器(P363)

除了 forward_list 外,其他容器都支持反向迭代器:

vector<int> vi = { 1,2,3,4,5 };
for (auto r_iter = vi.crbegin(); r_iter != vi.crend(); r_iter++) {cout << *r_iter << ' ';
}
// 输出5 4 3 2 1

利用反向迭代器和 sort 实现降序排序:

sort(vi.rbegin(), vi.rend());

反向迭代器需要递减运算符

反向迭代器的实现依赖于普通迭代器的 -- 运算符,除 forward_list 外,标准库中的所有容器都同时支持递增和递减操作。

反向迭代器和其他迭代器间的关系

假设我们有一个名为 linestring ,保存着一个逗号分隔的单词序列:

string line("FIRST,MIDDLE,LAST");

如果我们想要打印第一个单词,使用 find 可以很容易实现:

auto comma = find(line.cbegin(), line.cend(), ',');
cout << string(line.cbegin(), comma) << endl;    // 输出FIRST

如果我们想要打印最后一个单词,可以借助反向迭代器:

auto rcomma = find(line.crbegin(), line.crend(), ',');
cout << string(line.crbegin(), rcomma) << endl;    // 输出TSAL

可以发现,使用反向迭代器会导致我们的实际输出也是反过来的,所以我们需要使用 reverser_iteratorbase 函数成员,将反向迭代器转变成正向迭代器:

cout << string(rcomma.base(), line.cend()) << endl;    // 输出LAST

这里需要注意,反向迭代器 rcomma 指向 ',' ,而 rcomma 对应的普通迭代器 rcomma.base() 指向 'L' ,这一设计反映了“左闭右开区间”的特性:

95d215824a96d6f8ff0510b26ab0411

10.5 泛型算法结构(P365)

算法所要求的迭代器操作可以分为 5 个迭代器类别(iterator category):

635e475bc060fa70ae8b74e8d4cb4bc

10.5.1 5类迭代器(P365)

C++ 标准指明了算法的每个迭代器参数的最小类别,向算法传递一个能力更差的迭代器会产生错误

对于向算法传递错误类别迭代器的问题,很多编译器不会给出警告信息。

迭代器类别

输入迭代器(input iterator):可以读取序列中的元素,必须支持:

  • 用于比较两个迭代器==!=
  • 用于推进迭代器的前置和后置 ++
  • 用于读取元素的解引用运算符 * ,解引用只会出现在赋值运算符的右侧
  • 箭头运算符 ->

对于一个输入迭代器,*it++ 保证是有效的,但递增后可能导致其他指向流的迭代器失效,导致不能保证输入迭代器的状态可以保存下来用来访问元素。因此,输入迭代器只适用于单遍扫描算法。istream_iterator 是一种输入迭代器。

输出迭代器(output iterator):只写而不读元素,必须支持:

  • 用于推进迭代器的前置和后置 ++
  • 解引用运算符 * ,解引用只会出现在赋值运算符的左侧

输出迭代器只能用于单遍扫描算法,ostream_iterator 是一种输出迭代器。

前向迭代器(forward iterator):只能在序列中沿一个方向移动,可以读写元素,支持所有输入和输出迭代器的操作,可以多次读写同一个元素。因此,前向迭代器可以用于多遍扫描算法,forward_list 上的迭代器是前向迭代器。

双向迭代器(bidirectional iterator):可以双向移动,支持前向迭代器所有操作,支持前置和后置 -- 运算符。除 forward_list 外,所有标准库容器都提供符合双向迭代器要求的迭代器。

随机访问迭代器(random-access iterator):提供在常量时间内访问序列内任意元素的能力。除支持双向迭代器的所有功能,还支持:

  • 用于比较两个迭代器相对位置关系的运算符 >>=<<=
  • 迭代器和一个整数值的加减运算 ++=--=
  • 用于两个迭代器的减法运算符,得到两个迭代器的距离。
  • 下标运算符 iter[n] ,与 *(iter[n]) 等价。

arraydequestringvector 的迭代器都是随机访问迭代器,访问内置数组元素的指针也是。

10.5.2 算法形参形式(P367)

大多数算法具有如下 4 种形式之一:

alg(beg, end, args);
alg(beg, end, dest, args);
alg(beg, end, beg2, args);
alg(beg, end, beg2, end2, args);

begend 表示算法操作的输入范围。

接受单个目标迭代器的算法

dest 参数表示算法写入的目的位置的迭代器,并假定目标空间足够容纳写入的数据。比较常见的情况是,dest 绑定到一个插入迭代器或 ostream_iterator

接受第二个输入序列的算法

接受单独 beg2beg2end2 的算法用这些迭代器表示第二个输入范围 ,并假定 beg2 开始的范围至少begend 的范围一样大。

10.5.3 算法命名规范(P368)

一些算法使用重载形式传递一个谓词

unique(beg, end);
unique(beg, end, comp);

_if版本的算法

find(beg, end, val);
find_if(beg, end, pred);

由于可能产生重载歧义,所以标准库选择提供不同名字而非重载。

区分拷贝元素的版本和不拷贝的版本

reverse(beg, end);
reverse_copy(beg, end, dest);
vector<int> v1 = { 0,1,2,3,4,5 };
vector<int> v2;
// 同时提供_copy和_if版本
remove_copy_if(v1.begin(), v1.end(), back_inserter(v2),[](int i) {return i % 2; });
for (auto i : v1) cout << i << ' ';    // 输出0 1 2 3 4 5
cout << endl;
for (auto i : v2) cout << i << ' ';    // 输出0 2 4

10.6 特定容器算法(P369)

链表类型 listforward_list 定义了几个成员函数形式的算法:

3a7a5e75cd04504e75d58ae3a565dde 13c474e99772158945fc1406e0d2d1b

由于通用版本的 sort 要求随机访问迭代器,所以链表类型 listforward_list 只能使用专用版本;其他算法的通用版本虽然可以用于 listforward_list ,但这些算法需要交换序列中的元素,而链表可以通过改变元素间的链接方式实现交换,所以专用版本的算法效率往往更高。

splice成员

该算法是链表类型独有的:

73283381abaeef91df8024611e7a099

链表特有操作会改变容器

通用算法不会改变容器,而链表特有版本会改变底层容器。

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

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

相关文章

Selenium 连接到现有的 Google Chrome 示例

python 3.7 selenium 3.14.1 urllib3 1.26.8 Google Chrome 119.0.6045.160 (64位) chromedriver.exe 119.0.6045.105(win32) 1 Google Chrome 添加参数 "--remote-debugging-port9222" 2 测试效果(chromedriver.exe 要和 Google Chrome 版本…

vue3 router-view 使用keep-alive报错parentcomponent.ctx.deactivate is not a function

问题 如下图&#xff0c;在component组件上添加v-if判断&#xff0c;会报错: parentcomponent.ctx.deactivate is not a function 解决方法 去除v-if&#xff0c;将key直接添加上。由于有的公用页面&#xff0c;需要刷新&#xff0c;不希望缓存&#xff0c;所以需要添加key…

分支和循环

通常来说&#xff0c;C语言是结构化的程序设计语言&#xff0c;这里的结构包括顺序结构、选择结构、循环结构&#xff0c;C语言能够实现这三种结构&#xff0c;如果我们仔细分析&#xff0c;我们日常生活中所见的事情都可以拆分为这三种结构或者它们的组合。 下面我会仔细讲解我…

【人工智能Ⅰ】实验4:贝叶斯分类

实验4 贝叶斯分类 一、实验目的 1. 了解并学习机器学习相关库的使用。 2. 熟悉贝叶斯分类原理和方法&#xff0c;并对MNIST数据集进行分类。 二、实验内容 1. 使用贝叶斯方法对mnist或mnist variation数据集进行分类&#xff0c;并计算准确率。数据集从网上下载&#xff0…

vue.js ——Vuex

基本概念 vue进行开发过程中有没有遇到这样一种场景&#xff0c;就是有些时候一些数据是一种通用的共享数据&#xff08;比如登录信息&#xff09;&#xff0c;那么这类数据在各个组件模块中可能都会用到&#xff0c;如果每个组件中都去后台重新获取那么势必会造成性能浪费&am…

websocket 消息包粗解

最近在搞websocket解析&#xff0c;记录一下: 原始字符串 &#xfffd;~&#xfffd;{"t":"d","d":{"b":{"p":"comds/comdssqmosm7k","d":{"comdss":{"cmdn":"success",…

免费使用GPT的网站

登录ChatGPT系统 登录ChatGPT系统 登录ChatGPT系统

ArkTs变量类型、数据类型基础语法

可以参考官网学习路径学习HarmonyOS第一课|应用开发视频教程学习|HarmonyOS应用开发官网 ArkTS是华为自研的开发语言。它在TypeScript&#xff08;简称TS&#xff09;的基础上&#xff0c;匹配ArkUI框架&#xff0c;扩展了声明式UI、状态管理等相应的能力&#xff0c;让开发者以…

浅谈安科瑞ASJ继电器在菲律宾矿厂的应用

摘要&#xff1a;对电气线路进行接地故障保护&#xff0c;方式接地故障电流引起的设备和电气火灾事故越来越成为日常所需。针对用户侧主要的用能节点&#xff0c;设计安装剩余电流继电器&#xff0c;实时监控各用能回路的剩余电流状态。通过实时监控用能以及相关电力参数、提高…

ESP32-Web-Server编程- 通过 Highcharts 创建图表(Chart)实时显示设备信息

ESP32-Web-Server编程- 通过 Highcharts 创建图表&#xff08;Chart&#xff09;实时显示设备信息 概述 上节讲述了通过 Server-Sent Events&#xff08;以下简称 SSE&#xff09; 实现在网页实时更新 ESP32 Web 服务器的传感器数据&#xff0c;并通过表格显示传感器的数据。…

操作系统--中断异常

操作系统第一章易错总结 1.操作系统的功能 ⭐ 编译器是操作系统的上层软件&#xff0c;不是操作系统需要提供的功能。 ⭐注意&#xff1a; 1.批处理的主要缺点是缺乏交互性 2.输入/输出指令需要中断操作&#xff0c;中断必须在核心态下执行 3.多道性是为了提高系统利用率和…

【Spring MVC】Filter 过滤器异常处理 HandlerExceptionResolver 分析

文章目录 前言版本说明测试 Demo1、自定义过滤器 DemoFilter2、自定义业务异常 ServiceException3、自定义异常处理类 DemoExceptionHandler4、DemoController5、请求测试 问题分析1、日志打印记录2、Debug 方法 解决方案1、修改自定义过滤器2、请求测试 解决方案分析1、日志打…

提升技能素养,AMCAP做出合适的决策

近年来&#xff0c;智能配置投资与理财逐渐受到关注并走俏。这是一种简单快捷的智慧化理财方式&#xff0c;通过将个人和家族的闲置资金投入到低风险高流动性的产品中。 国际财富管理投资机构AMCAP集团金融分析师表示&#xff1a;智能配置投资与理财之所以持续走俏&#xff0c…

6.3 Windows驱动开发:内核枚举IoTimer定时器

内核I/O定时器&#xff08;Kernel I/O Timer&#xff09;是Windows内核中的一个对象&#xff0c;它允许内核或驱动程序设置一个定时器&#xff0c;以便在指定的时间间隔内调用一个回调函数。通常&#xff0c;内核I/O定时器用于周期性地执行某个任务&#xff0c;例如检查驱动程序…

在Linux上安装KVM虚拟机

一、搭建KVM环境 KVM&#xff08;Kernel-based Virtual Machine&#xff09;是一个基于内核的系统虚拟化模块&#xff0c;从Linux内核版本2.6.20开始&#xff0c;各大Linux发行版就已经将其集成于发行版中。KVM与Xen等虚拟化相比&#xff0c;需要硬件支持的完全虚拟化。KVM由内…

使用 kubeadm 部署 Kubernetes 集群(一)linux环境准备

一、 初始化集群环境 准备三台 rocky8.8 操作系统的 linux 机器。每台机器配置&#xff1a;4VCPU/4G 内存/60G 硬盘 环境说明&#xff1a; IP 主机名 角色 内存 cpu 192.168.1.63 xuegod63 master 4G 4vCPU 192.168.1.64 xuegod64 worker 4G 4vCPU 192.168.1.62 xuegod62 work…

Python 异常处理(try except)

文章目录 1 概述1.1 异常示例 2 异常处理2.1 捕获异常 try except2.2 抛出异常 raise 3 异常类型3.1 内置异常3.2 自定义异常 1 概述 1.1 异常示例 异常&#xff1a;程序执行中出现错误&#xff0c;若不处理&#xff0c;则程序终止 示例代码&#xff1a; v 6 / 0 # 除数不…

基于matlab的图像去噪算法设计与实现

摘 要 随着我们生活水平的提高&#xff0c;科技产品飞速更新换代&#xff0c;在信息传输中&#xff0c;图像传输所占的比重越来越大。但自然噪声会在图像传输时干扰其传输过程&#xff0c;甚至会使图片不能表达其原来的意义。去噪处理就是为了去除图像中的噪声&#xff0c;从而…

【数据清洗 | 数据规约】数据类别型数据 编码最佳实践,确定不来看看?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

tex2D使用学习

1. 背景&#xff1a; 项目中使用到了纹理进行插值的加速&#xff0c;因此记录一些自己在学习tex2D的一些过程 2. 代码&#xff1a; #include "cuda_runtime.h" #include "device_launch_parameters.h" #include <assert.h> #include <stdio.h>…