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

news2024/11/15 1:43:44

参考资料:

  • 《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.coloradmin.cn/o/1273234.html

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

相关文章

Selenium定位元素的方法css和xpath的区别!

selenium是一种自动化测试工具&#xff0c;它可以通过不同的定位方式来识别网页上的元素&#xff0c;如id、name、class、tag、link text、partial link text、css和xpath。 css和xpath是两种常用的定位方式&#xff0c;它们都可以通过元素的属性或者层级关系来定位元素&#…

【UE】UEC++委托代理

【UE】UEC委托代理 一、委托的声明与定义 #pragma once#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "DelegateGameMode.generated.h"// // Declare DECLARE_DELEGATE // DECLARE_DELEGATE(FDeclareDelegate_…

Python中的Slice函数:灵活而强大的序列切片技术

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Python中的Slice函数是一种强大且灵活的序列切片技术&#xff0c;用于从字符串、列表、元组等序列类型中提取子集。本文将深入研究Slice函数的功能和用法&#xff0c;提供详细的示例代码和解释&#xff0c;帮助读…

java操作windows系统功能案例(一)

下面是一个Java操作Windows系统功能的简单案例&#xff1a; 获取系统信息&#xff1a; import java.util.Properties;public class SystemInfo {public static void main(String[] args) {Properties properties System.getProperties();properties.list(System.out);} }该程…

【智能家居】三、添加语音识别模块的串口读取功能点

语音识别模块SU-03T 串口通信线程控制代码 inputCommand.h&#xff08;输入控制指令&#xff09;voiceControl.c&#xff08;语音控制模块指令&#xff09;main.c&#xff08;主函数&#xff09;编译运行结果 语音识别模块SU-03T AI智能语音识别模块离线语音控制模块语音识别…

以STM32CubeMX创建DSP库工程方法一

以STM32CubeMX创建DSP库工程方法 略过时钟树的分配和UART的创建等&#xff0c;直接进入主题生成工程文件 它们中的文件功能如下&#xff1a; 1&#xff09;BasicMathFunctions 基本数学函数&#xff1a;提供浮点数的各种基本运算函数&#xff0c;如向量加减乘除等运算。 2&…

基于SSM框架的餐馆点餐系统的设计

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

11.30 C++类特殊成员函数

#include <iostream>using namespace std; class Per { private:string name;int age;double *high;double weight; public://构造函数Per(string name,int age,double high,double weight):name(name),age(age),high(new double(high)),weight(weight){cout << &q…

ECONGU4280 Corporate Finance

ECONGU4280 Corporate Finance WeChat: zh6-86

Linux系统编程 day07 信号

Linux系统编程 day07 信号 1. 信号的介绍以及信号的机制2. 信号相关函数2.1 signal2.2 kill2.3 abort和raise2.4 alarm2.5 setitimer 3. 信号集4. 信号捕捉函数6. SIGCHLD信号7. SIGUSR1与SIGUSR2 1. 信号的介绍以及信号的机制 信号是信息的载体&#xff0c;在Linux/Unix环境下…

对话 AI for Science 先行者,如何抓住科研范式新机遇?丨和鲸社区2023年度科研闭门会

2023年3月&#xff0c;科技部会同自然科学基金委启动了 AI for Science 的专项部署工作。数据驱动的科学研究长期以来面临着诸多困境&#xff0c;针对传统科研工作流中过度依赖人类专家经验与体力的局限性&#xff0c;AI for Science 旨在基于科学数据与算力支撑&#xff0c;通…

香港高端人才通行证计划入围高校名单公布,如何申请?

香港高端人才通行证计划入围高校名单公布&#xff0c;如何申请&#xff1f; 高端人才通行证计划&#xff08;英语&#xff1a;Top Talent Pass Scheme (TTPS)&#xff09;&#xff0c;简称“高才通计划”&#xff0c;是香港为了吸引世界各地具备丰富工作经验及高学历的高端人才…

力扣题:单词-11.20

力扣题-11.20 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;58. 最后一个单词的长度 解题思想&#xff1a;按空格划分&#xff0c;然后统计单词长度即可 class Solution(object):def lengthOfLastWord(self, s):""":type s: str…

2021年6月23日 Go生态洞察:Stack Overflow上的Go集体

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

安全高效的PostgreSQL数据库迁移解决方案

PostgreSQL数据库是一款高度可扩展的开源数据库系统&#xff0c;支持复杂的查询、事务完整性和多种数据类型&#xff0c;这使得它成为企业中处理大规模和多样化数据需求的理想选择。在很多企业中&#xff0c;PostgreSQL不仅处理大量的交易数据&#xff0c;还支持复杂的数据分析…

java开发之基于个微群聊二次开发

请求URL&#xff1a; http://域名地址/getGroupQrCode 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wId是String登录实例标识chatRoomI…

C++ 单词拆分

题目1&#xff1a;139 单词拆分 题目链接&#xff1a;单词拆分 对题目的理解 字符串列表wordDict作为字典&#xff0c;判断是否可以利用字典中出现的单词拼接出字符串s&#xff0c;字典中的单词可以重复使用&#xff0c;题目中字符串s的长度至少为1&#xff0c;不存在空字符…

YOLOv5独家原创改进: AKConv(可改变核卷积),即插即用的卷积,效果秒杀DSConv | 2023年11月最新发表

💡💡💡本文全网首发独家改进:可改变核卷积(AKConv),赋予卷积核任意数量的参数和任意采样形状,为网络开销和性能之间的权衡提供更丰富的选择,解决具有固定样本形状和正方形的卷积核不能很好地适应不断变化的目标的问题点,效果秒殺DSConv 1)AKConv替代标准卷积进行…

Attacking Fake News Detectors via Manipulating News Social Engagement(2023 WWW)

Attacking Fake News Detectors via Manipulating News Social Engagement----《通过操纵新闻社交互动来攻击假新闻检测器》 摘要 在年轻一代中&#xff0c;获取新闻的主要来源之一是社交媒体。随着新闻在各种社交媒体平台上日益流行&#xff0c;虚假信息和毫无根据的言论的传…

GPU逻辑管线

文章目录 前言一、渲染流水线二、英伟达显卡简化概念图&#xff08;GPU&#xff09;1、我们的Shader会调用英伟达提供的 API2、调用API后&#xff0c;把Shader用到的指令存储在Pushbuffer中3、然后图元分配器&#xff0c;会把 模型数据 和 Shader 指令传入GPU中4、这个SM是每个…