10-5 泛型算法结构
10.5.1 5类迭代器
按操作分类,形成了一种层次,高类别的迭代器支持低类别的所有操作
对于向一个算法传递错误类别的迭代器的问题,很多编译器不会给出任何警告或提示。
输入迭代器(input iterator)#
输入迭代器必须支持
- 用于比较两个迭代器的相等和不相等运算符(==、!=)
- 用于推进迭代器的前置和后置递增运算(++)
- 用于读取元素的解引用运算符(*);解引用只会出现在赋值运算符的右侧
- 箭头运算符(->),等价于(*it) .member,即,解引用迭代器,并提取对象的成员
输入迭代器只用于顺序访问。
对于一个输入迭代器,*it++保证是有效的,但递增它可能导致所有其他指向流的迭代器失效。其结果就是,不能保证输入迭代器的状态可以保存下来并用来访问元素。
因此,输入迭代器只能用于单遍扫描算法。算法 find和 accumulate要求输入迭代器;而istream_iterator是一种输入迭代器。
输出迭代器(output iterator)#
输出迭代器必须支持:
- 用于推进迭代器的前置和后置递增运算(++)
- 解引用运算符(*),只出现在赋值运算符的左侧(向一个已经解引用的输出迭代器赋值,就是将值写入它所指向的元素)
我们只能向一个输出迭代器赋值一次。类似输入迭代器,输出迭代器只能用于单遍扫描算法。用作目的位置的迭代器通常都是输出迭代器。
例如,copy函数的第三个参数就是输出迭代器。ostream_iterator类型也是输出迭代器。
前向迭代器(forward iterator)#
可以读写元素。这类迭代器只能在序列中沿一个方向移动。
前向迭代器支持所有输入和输出迭代器的操作,而且可以多次读写同一个元素。
因此,我们可以保存前向迭代器的状态,使用前向迭代器的算法可以对序列进行多遍扫描。
算法replace要求前向迭代器,forward_list上的迭代器是前向迭代器。
双向迭代器(bidirectional iterator)#
可以正向/反向读写序列中的元素。
除了支持所有前向迭代器的操作之外,双向迭代器还支持前置和后置递减运算符(--)。
算法 reverse要求双向迭代器,除了forward_list 之外,其他标准库都提供符合双向迭代器要求的迭代器。
随机访问迭代器(random-access iterator)#
提供在常量时间内访问序列中任意元素的能力。此类迭代器支持双向迭代器的所有功能,此外还支持如下的操作:
- 用于比较两个迭代器相对位置的关系运算符(<、<=、>和>=)
- 迭代器和一个整数值的加减运算(+、+=、-和-=),计算结果是迭代器在序列中前进(或后退)给定整数个元素后的位置
- 用于两个迭代器上的减法运算符(-),得到两个迭代器的距离
- 下标运算符(iter[n]),与* (iter[n])等价
算法sort要求随机访问迭代器。array、deque、string 和 vector的迭代器都是随机访问迭代器,用于访问内置数组元素的指针也是。
10.5.2 算法的形参模式
大多数算法具有如下四种形式之一
其中alg是算法的名字,beg和 end表示算法所操作的输入范围。
几乎所有算法都接受个输入范围,是否有其他参数依赖于要执行的操作。
这里列出了常见的一种——destvbeg2和 end2,都是迭代器参数。顾名思义,如果用到了这些迭代器参数,它们分别承担指定目的位置和第二个范围的角色。除了这些迭代器参数,一些算法还接受额外的、非迭代器的特定参数。
接受单个目标迭代器的算法#
dest参数是一个表示算法可以写入的目的位置的迭代器。算法假定(assume):按其需要写入数据,不管写入多少个元素都是安全的。
保证写入的目标容器有足够的空间是程序员的责任,通常会将dest设置为插入迭代器,这样就能保证空间是足够的
接受第二个输入序列的算法#
接受单独beg2的算法假定从 beg2开始的序列与beg和end所表示的范围至少一样大。
10.5.3 算法的命名规范
除了参数规范,算法还遵循一套命名和重载规范。
这些规范处理诸如:如何提供一个操作代替默认的<或==运算符以及算法是将输出数据写入输入序列还是一个分离的目的位置等问题。
一些算法使用重载形式传递一个谓词#
接受谓词参数来代替<或==运算符的算法,以及那些不接受额外参数的算法,通常都是重载的函数。
unique(beg, end);//使用==比较元素
unique(beg, end, comp); //使用谓词比较元素
_if版本的算法#
接受一个元素值的算法通常有另一个不同名的(不是重载的)版本,该版本接受一个谓词代替元素值。
find(beg, end, val); //查找输入范围中第一个val的位置
find(beg, end, pred); //查找第一个令pred为真的元素的位置
区分拷贝元素的版本和不拷贝元素的版本#
默认情况下,重排元素的算法将重排后的元素写回给定的输入序列中。
这些算法还提供另一个版本,将元素写到一个指定的输出目的位置。此时需要加后缀_copy
reverse(beg, end); //反转输入范围中的元素
reverse_copy(beg, end, dest); //将元素逆序拷贝到dest
有些算法同时提供_copy和_if版本
//删除v1中的奇数元素
remove_if(v1.begin(), v1.end(), [](int i){return i%2;});
//将偶数元素从v1拷贝到v2;v1不变
remove_copy_if(v1.begin(), v1.end(), back_inserter(v2),
[](int i){return i%2;});
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战