初识泛型算法
只读算法
accumulate 函数接受三个参数,前两个指出了需要求和的元素的范围,第三个参数是和的初值:
//对vec中的元素求和,和的初值是0
int sum = accumulate(vec.cbegin(), vec.cend(), 0);
算法和元素类型
序列中元素的类型必须与第三个参数匹配,或者能够转换为第三个参数的类型。
string 定义了 + 运算符,可以通过调用 accumulate 将 vector 中所有 string 元素连接起来:
string num = accumulate(v.cbegin(), v.cend(), string(""));
通过第三个参数显式地创建了一个 string。
将空串当作一个字符串字面值传递给第三个参数是不可以的:
//错误:const char* 上没有定义 + 运算符
string sum = accumulate(v.cbegin(), v.cend(), "");
用于保存和对象的类型将是 const char*,此类型决定了使用哪个 + 运算符,const char*没有 + 运算符。
操作两个序列的算法
equal 用于确定两个序列是否保存相同的值。如果所有对应元素都相等,则返回true,否则返回false。
前两个表示第一个序列中的元素范围,第三个表示第二个序列的首元素:
//roster2中元素的数目应该至少与roster1一样多
equal(roster1.cbegin(), roster2.cend(), roster2.cbegin());
元素类型不必一样,能用 == 来比较元素类型即可。
roster1 可以是vector<string>,而 roster2 是list<const char*>。
equal 基于一个非常重要的假设:假定第二个序列至少与第一个序列一样长。
只接受一个单一迭代器来表示第二个序列的算法,都假定第二个序列至少与第一个序列一样长。
写容器元素的算法
算法 fill 接受一对迭代器表示一个范围,还接受一个值作为第三个参数。
fill 将给定的这个值赋予输入序列中的每个元素:
//将每个元素重置为0
fill(vec.begin(), vec.end(), 0);
//将容器的一个子序列设置为10
fill(vec.begin(), vec.begin() + vec.size()/2, 10);
算法不检查写操作
函数fill_n接受一个单迭代器、一个计数值和一个值,将给定值赋予迭代器指向的元素开始的指定个元素:
//空vector
vector<int> vec;
//使用vec,赋予它不同值
fill_n(vec.begin(), vec.size(), 0);//将所有元素重置为0
函数fill_n假定写入指定个元素是安全的,如下形式的调用:
fill_n(dest, n, val)
容易犯错点:在一个空容器上调用 fill_n:
vector<int> vec;//空向量
//修改vector中的10个不存在的元素
fill_n(vec.begin(), 10, 0);
介绍 back_inserter
back_inserter 定义在头文件 iterator 中的一个函数
接受一个指向容器的引用,返回一个与容器绑定的插入迭代器,通过此迭代器赋值时,赋值运算符会调用push_back将一个具有给定值的元素添加到容器中:
vectror<int> vec;//空向量
auto it = back_inserter(vec);//通过它赋值会将元素添加到vec中
*it = 42;//vec中现在有一个元素,值为42
用 back_inserter 创建一个迭代器,作为算法的目的位置来使用:
vector<int> vec;//空向量
//正确:back_inserter创建一个插入迭代器,可用来向vec添加元素
fill_n(back_inserter(vec), 10, 0);//添加10个元素到vec
拷贝算法
copy算法接受三个迭代器,前两个表示一个输入范围,第三个表示目的序列的起始位置。此算法将输入范围中的元素拷贝到目的序列中,传递给copy的目的序列至少要包含与输入序列一样多的元素。
用copy实现内置数组的拷贝:
int a1[] = {0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1)/sizeof(*a1)];//a2与a1一样的大小
//ret指向拷贝到a2的尾元素之后的位置
auto ret = copy(begin(a1), end(a1), a2);//把a1的内容拷贝给a2
copy 返回的是其目的位置迭代器递增后的值,ret 恰好指向拷贝到 a2 的尾元素之后的位置。
replace 算法读入一个序列,并将其中所有等于给定值的元素都改为另一个值。
算法接受4个参数:前两个是迭代器,表示输入序列,后两个一个是要搜索的值,另一个是新值。
//将所有值为0的元素改为42
replace(ilst.begin(), ilst.end(), 0, 42);
replace_copy保留原序列不变,接受额外第三个迭代器参数,指出调整后序列的保存位置:
//使用back_inserter按需要增长目标序列
replace_copy(ilst.begin(), ilst.end(), back_inserter(ivec), 0, 42);
重排容器元素的算法
简单的故事输入:
the quick red fox jumps over the slow red turtle
生成如下 vector:

消除重复单词
- 将 vector 排序,使得重复的单词都相邻出现。
- 用 unique 算法来重排 vector,使不重复的元素出现在 vector 的开始部分。
- 用 vector 的成员 erase 成员来完成删除操作。
void elimDups(vector<string> &words)
{
//按字典排序words,以便查找重复单词
sort(words.begin(), words.end());
//unique重排输入范围,使得每个单词只出现一次
//排序在范围的前部,返回指向不重复区域之后一个位置的迭代器
auto end_unique = unique(words.begin(),words.end());
//使用向量操作erase删除重复单词
words.erase(end_unique,words.end());
}
完成 sort 后 words 的顺序:

使用 unique
调用 unique 后 vector:

words 的大小并未改变,unique 覆盖相邻的重复元素,返回的迭代器指向最后一个不重复元素之后的位置。
使用容器操作删除元素
erase 删除从 end_unique 开始直至 words 末尾的范围内的所有元素。
words 中没有重复单词,unique 会返回 words.end(),传递给 erase 的元素范围为空,删除一个空范围没有不良后果。

浙公网安备 33010602011771号