泛型算法总结

泛型算法

1. 简介

1.1定义

泛型:可以操作在不同的容器类型之上。

算法:实现共同的操作。

注意:大多数算法是通过遍历由两个迭代器标记的一段元素来实现其功能。

1.泛型算法本身从不执行容器提供的操作,只是单独依赖迭代器和迭代器操作实现。

2.使用“普通”的迭代器时,算法从不修改基础容器的大小。正如我们看到的,算法也许会改变存储在容器中元素的值,也许会在容器内移动元素,但是,算法从不直接添加或删除元素。

2.根据对元素的操作将算法分类

头文件:

#include <algorithm>

#include <numeric>

2.1 只读算法

find()

accumulate(b, e, t)                    b, e均为迭代器,指定要累加的元素范围,t为累加的起始值

注意:accumulate算法返回累加的结果,其返回类型就是其第三个实参的类型

1. 调用该函数时必须传递一个起始值,否则,accumulate将不知道使用什么起始值

2. 容器内的元素类型必须与第三个实参的类型匹配,或者可以转换为第三个实参的类型。

find_first_of(b1, e1, b2, e2)     b1,e1和b2,e2为两组迭代器,分别标记两段元素范围,在第一段范围内查找与第二段范围中任意元素匹配的元素,然后返回一个迭代器,指向第一个匹配的元素。

                                                                 注意:每对迭代器中,两个实参的类型必须精确匹配,但不要求两对之间的类型匹配,特别是,元素可存储在不同类型的序列中,只要这两个序列的元素可以比较。

2.2 写容器元素的算法

注意:在使用写入元素的算法时要当心,必须确保算法缩写的序列至少足以存储要写入的元素。

2.2.1 写入输入序列的元素

fill(b, e, t)                                              b,e为一对迭代器,指定要写入的范围,t为将范围内的元素设定成的值。

注意:如果输入范围有效,则可安全写入。这个算法只会对输入范围内已存在的元素进行写入操作。

2.2.2 不检查写入操作的算法

fill_n(b, n, t)                                          从迭代器b指向的元素开始,将指定数量n的元素设置成给定的值t

注意:fill_n函数假定对指定数量的元素做写操作时安全的,如果容器为空,或者不足以存放指定数量n的元素,那么将会发生灾难性的后果。

确保算法有足够的元素存储输入数据的一种方法是使用插入迭代器(insert iterator)

头文件:

#include<iterator>

fill_n(back_inserter(vec),n, t) 通过back_inserter实现,相当于调用vec.push_back(n)实现。

2.2.3 写入到目标迭代器的算法

copy(ilist.begin(),ilist.end(), back_inserter(ivec))                    从输入范围中读取元素,然后将它们复制给目标ivec

2.2.4 算法的_copy版本

这些算法对输入序列的元素做出处理,但不修改原来的元素,而是创建一个新序列存储元素的处理结果。

举例:

replace(b, e, t1, t2)                      将迭代器b,e范围内的t1全部替换成t2。

replace_copy(b, e,back_inserter(ivec), t1, t2)        

将迭代器b,e范围内的t1全部替换成t2,但是不修改原来的序列,而是将修改后的序列存储到迭代器指定的副本中。

unique(b, e)                                           去除迭代器b, e范围内重复的元素

unique_copy(b, e, back_inserter(ivec))

将迭代器b,e范围内重复的元素去掉,但是不修改原来的序列,而是将修改的序列存储到迭代器指定的副本中。

 

2.3 对容器元素重新排序的算法

sort(b, e)                                                b,e标记要排序的范围

stable_sort(b, e, predicate)              b,e标记要排序的范围,predicate谓词。

注意:谓词是做某些检测的函数,返回用于条件判断的类型,支出条件是否成立。

3.另外三种迭代器介绍

头文件:

#include <iterator>

3.1 插入迭代器(insert iterator)

定义:这类迭代器与容器绑定在一起,实现在容器中插入元素的功能。

back_inserter(C)                                  创建使用push_back实现插入的迭代器。

front_inserter(C)                                 使用push_front实现插入。

注意:只有在容器提供了push_front操作的时候才能使用front_inserter,否则会发生错误。inserter(C,it)                                         将产生在指定位置实现插入的迭代器。    

3.2  iostream迭代器

定义:这类迭代器可与输入或输出流绑定在一起,用于迭代遍历所关联的IO流。

这些迭代器将他们所对应的流是为特定类型的元素序列。使用流迭代器是,可以用泛型算法从流对象中读数据(或将数据写入到流对象中)。

3.2.1  iostream迭代器的构造函数

istream_iterator<T> in(strm);               创建从输入流strm中读取T类型对象的istream_iterator对象。

istream_iterator<T>  in;                           istream_iterator对象的超出末端迭代器

ostream_iterator<T> in(strm);              创建将T类型的对象写到输出流strm的ostream_iterator对象

ostream_iterator<T > in(strm, delim);         创建将T类型的对象写到输出流strm的ostream_iterator对象,在写入过程中使用delim作为元素的分隔符。delim是以空字符结束的字符数组。              

 

3.2.2  istream对象和ostream对象的使用

使用方法,概括来说就是将流对象iostream看做一种容器,然后用iostream迭代器进行操作。

3.2.3 流迭代器的限制

1. 不可能从ostream_iterator对象读入,也不可能写到istream_iterator对象中。

2. 一旦给ostream_iterator对象服了一个值,写入就提交了。赋值后,没有办法再改变这个值。此外,ostream_iterator对象中每个不同的值都只能正好输出一次。

3. ostream_iterator没有-> 操作。

 

3.3 反向迭代器(reverse iterator)

定义:这类迭代器实现向后遍历,而不是向前遍历。所有容器类型都定义了自己的reverse_iterator类型,由rbegin和rend成员函数返回。

所有容器都定义了begin和end成员,分别返回指向容器首元素和尾元素下一位置的迭代器。

容器还定义了rbegin和rend成员,分别返回指向容器尾元素和首元素前一位置的反向迭代器。

使用:类比普通迭代器。

4.迭代器的分类

算法要求的迭代器操作分为五个类别,对应如下列出的五种迭代器:

输入迭代器                                 读,不能写;只支持自增运算

输出迭代器                                 写,不能读;只支持自增运算

前向迭代器                                 读和写;只支持自增运算

双向迭代器                                 读和写;支持自增和自减运算

随机访问迭代器                       读和写;支持完整的迭代器算术运算

注意:对于每一个形参,迭代器必须保证最低功能。将支持更少功能的迭代器传递给函数是错误的,而传递更强功能的迭代器则没有问题。

5.根据需要使用的迭代器种类对算法进行分类

5.1 算法的形参模式

分为四种:

alg(beg, end, other parms);

alg(beg, end, dest, other parms);

alg(beg, end, beg2, other parms);

alg(beg, end, beg2, end2, other parms);

alg是算法的名字,beg和end指定算法操作的元素范围。通常称为算法的“输入范围”,

其它形参:dest 、beg2、end2它们都是迭代器。

5.1.1 带有单个目标迭代器的算法

dest形参是一个迭代器,用于指定存储输出数据的目标对象。

注意:算法假定无论需要写入多少个元素都是安全的。

调用这些算法时,必须确保输出容器有足够大的容量存储输出数据,这正是通常要使用插入迭代器或者ostream_iterator来调用这些算法的原因。

5.1.2带第二个输入序列的算法

这类算法通常将联合两个输入范围的元素来完成计算功能。

带beg2和end2的算法,完整地指定了两个输入范围:(beg, end)和(beg2, end2)。

不带end2的算法,只指定了首元素,而没有指定该范围的最后一个元素。

注意:与写入dest的算法一样,只带有beg2的算法也假定以beg2开始的序列与begend标记的序列一样大。

5.2 算法的命名规范

5.2.1第一种模式:测试输入范围内元素的算法

区别带有一个值或一个谓词函数参数的算法版本

举例:

当参数个数不同的时候,使用谓词函数的算法多一个参数:

sort(beg,end)              普通排序,用到标准库的关系操作符:==和<

sort(beg,end, comp)        谓词函数comp(),来提供比较来取代操作符的使用

注意:当参数个数相同的时候,使用谓词函数的算法后面加上_if来加以区别:

find(beg,end, val)

find_if(beg,end, pred)    

5.2.2第二种模式:应用于对输入范围内元素重新排序的算法

举例:

reverse(beg, end)                                         将重新排列的算法写回其输入范围

reverse_copy(beg, end, dest)                    将重新排列后的元素写入到指定的输出目标

注意:是否改变原来的输入序列的元素通过_copy来区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值