大多数的算法都有如下四种形式:
alg(beg, end, args); alg(beg, end, dest, args); alg(beg, end, beg2, args); alg(beg, end, beg2, end2, args);
其中alg是算法的名字,beg和end表示算法所操作的范围。几乎所有的算法都要接受一个数出范围,是否有其它的参数依赖于要具体执行的操作。这里的beg, beg2, end, end2, dest都是迭代器参数。因此我们说迭代器有很大一部分都是在为泛型算法服务的。
接受单个目标的迭代器算法dest参数是一个表述算法可以写入的目的位置的迭代器。算法假定:无论像其写入多少个元素,都是安全的,不会发生溢出等情况。这就要求程序员自己为写入的对象分配足够的空间来确保安全。
dest如果是一个直接指向容器的迭代器,那么算法会将输出的数据写到容器中已存在的元素内,也就是说,原先的数据很可能会被覆盖甚至会溢出,如果容器不为空的话,那么这种情况显然是我们不愿意看见的。因此我们通常将dest设置为这两类迭代器:插入迭代器和ostream_iterator。插入迭代器是将新元素插入到容器中,因此无论算法输出多少元素,空间都是足够的。而ostream_iterator会将数据写入输出流,同样无论写多少数据都没有问题。
vector接受第二个输入序列的算法ivec1 = {1, 2, 3, 4, 5, 6, 7}; vector ivec2 = {8, 9, 10} ostream_iterator int_ot(cout, " "); // 输出1 2 3 4 5 6 7 copy(ivec1.begin(). ivec1.end(), int_ot); copy(ivec1.begin(), ivec1.end(), back_inserter(ivec2)); // 输出8 9 10 1 2 3 4 5 6 7 copy(ivec2.begin(), ivec2.end(), int_ot);
接受单独的beg2或者beg2和end2一起的算法用这些迭代器表示第二个输入范围,它通常和第一个输入范围结合在一起进行一些运算。
如果一个算法接受beg2和end2,这两个迭代器表示一个完整指定的第二输入范围。
如果一个算法只接受beg2,那么他的第二个输入范围的结束位置未指定,一般来说,算法假定从beg2开始到结束位置的范围和从beg开始到end结束的范围一样大。
算法命名规范除了参数范围,算法还遵循着一套命名规范和重载规范,这些规范处理诸如如何提供一个操作代替默认的<或者==运算符已经算法试讲输出数据写入一个序列内还是一个分离的目的位置等问题。
一些算法使用重载形式传递一个谓词接受谓词参数来代替<和==运算符的算法,已经那些不接受额外参数的算法,通常都是重载函数。函数的一个版本用元素类型的运算符来比较元素;另一个版本接受一个额外的谓词参数来代替<或者==
unique(beg, end); // 使用==运算符来比较元素 unique(beg, end, comp); // 使用谓词comp来比较元素
两个调用都是重新整理给定的序列,将相邻的重复元素删除。第一个调用直接使用==运算符来检查重复的元素;第二个则调用comp来判断元素是否相等。这样做的目的便是两个重载函数的参数个数不相等,因此具体应该调用哪个版本时就不会出现二义性了。
_if版本的算法接受一个元素值的算法通常由另一个不同名的版本,该版本不是重载版本,该版本接受一个谓词来代替元素的值,接受谓词参数的算法都有附加的_if后缀
find(beg, end, val); // 查找输入范围内val第一次出现的位置 find_if(beg, end, pred); // 查找输入范围内第一个令pred为真的元素的位置
这两个算法提供了命名上的差异,因为他们都能接受相同数目的参数,用命名上的差异而不是重载函数是为了避免任何肯恩过的二义性。
拷贝版本和非拷贝版本默认情况下,重排元素的算法会将重拍后的元素协会给定的输入序列中。当然,这些算法那还提供了另外一个版本,将元素写到一个指定的输出目的位置。这些算法都后缀一个_copy
reverse(beg, end); // 翻转输入的序列 reverse_copy(beg, end, dest); // 将翻转的序列拷贝到dest // 下面是_if和_copy连用的例子 remove_if_copy(beg, end, dest, pred) // 将令pred为真的元素删除,剩下的元素拷贝到dest中



