泛型算法的结构

算法的形参模式

任何其他的算法分类都含有一组形参规范。理解这些形参规范有利于学习新的算法——只要知道形参的含义,就可专注于了解算法实现的操作。大多数算法采用下面四种形式之一:

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,它们都是迭代器。这些迭代器在使用时,充当类似的角色。除了这些迭代器形参之外,有些算法还带有其他的菲迭代器形参,它们是这些算法特有的。

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

dest 形参是一个迭代器,用于指定存储输出数据的目标对象。算法假定无论需要写入多少个元素都是安全的。

调用这些算法时,必须确保输出容器有足够大的容量存储输出数据,这正是通常要使用插入迭代器或者 ostream_iterator来调用这些算法的原因。如果使用容器迭代器调用这些算法,算法将假定容器里有足够多个需要的元素。

如果 dest 是容器上的迭代器,则算法将输出内容写到容器中已存在的元素上。更普遍的用法是,将 dest 与某个插入迭代器或者ostream_iterator 绑定在一起。插入迭代器在容器中添加元素,以确保容器有足够的空间存储输出。ostream_iterator 则实现写输出流的功能,无需要考虑所写的元素个数。

带第二个输入序列的算法

有一些算法带有一个 beg2 迭代器形参,或者同时带有 beg2 和 end2 迭代器形参,来指定它的第二个输入范围。这类算法通常将联合两个输入范围的元素来完成计算功能。算法同时使用 beg2 和 end2 时,这些迭代器用于标记完整的第二个范围。也就是说,此时,算法完整地指定了两个范围:beg 和 end 标记第一个输入范围,而 beg2 和 end2 则标记第二个输入范围。

带有 beg2 而不带 end2 的算法将 beg2 视为第二个输入范围的首元素,但没有指定该范围的最后一个元素。这些算法假定以 beg2 开始的范围至少与 beg和 end 指定的范围一样大。

与写入 dest 的算法一样,只带有 beg2 的算法也假定以 beg2开始的序列与 beg 和 end 标记的序列一样大。

算法的命名规范

区别带有一个值或一个谓词函数参数的算法版本很多算法通过检查其输入范围内的元素实现其功能。这些算法通常要用到标准关系操作符:== 或 <。其中的大部分算法会提供第二个版本的函数,允许程序员提供比较或测试函数取代操作符的使用。

重新对容器元素排序的算法要使用 < 操作符。这些算法的第二个重载版本带有一个额外的形参,表示用于元素排序的不同运算:

sort (beg, end); // use < operator to sort the elements
sort (beg, end, comp); // use function named comp to sort the elements

检查指定值的算法默认使用 == 操作符。系统为这类算法提供另外命名的(而非重载的)版本,带有谓词函数形参。带有谓词函数形参的算法,其名字带有后缀 _if:

find(beg, end, val); // find first instance of val in the input range
find_if(beg, end, pred); // find first instance for which pred is true

上述两个算法都在输入范围内寻找指定元素的第一个实例。其中,find 算法查找一个指定的值,而 find_if 算法则用于查找一个使用谓词函数 pred 返回非零值的元素。

标准库为这些算法提供另外命名的版本,而非重载版本,其原因在于这个两种版本的算法带有相同数目的形参。对于排序算法,只要根据参数的个数就很容易消除函数调用的歧义。而对于查找指定元素的算法,不管检查的是一个值还是谓词函数,函数调用都需要相同个数的参数。此时,如果使用重载版本,则可能导致二义性(第 7.8.2 节),尽管这个可能出现的几率很低。因此,标准库为这些算法提供两种不同名字的版本,而没有使用重载。

区别是否实现复制的算法版本

无论算法是否检查它的元素值,都可能重新排列输入范围内的元素。在默认情况下,这些算法将重新排列的元素写回其输入范围。标准库也为这些算法提供另外命名的版本,将元素写到指定的输出目标。此版本的算法在名字中添加了_copy 后缀:

reverse(beg, end);
reverse_copy(beg, end, dest);

reverse 函数的功能就如它的名字所意味的:将输入序列中的元素反射重新排列。其中,第一个函数版本将自己的输入序列中的元素反向重排。而第二个版本,reverse_copy,则复制输入序列的元素,并将它们逆序存储到 dest 开始的序列中。

posted @ 2018-05-10 22:56  刘-皇叔  阅读(185)  评论(0)    收藏  举报