C++ primer第十章—泛型算法

10.1 概述

  1. 大多数算法都定义在头文件algorithm中。标准库还在头文件numeric中定义了一组数值泛型算法
  2. 算法并不是直接操作容器,而是遍历有两个迭代器指定的一个元素范围,迭代器令算法不依赖于容器,find用元素类型的==运算符完成每个元素与给定值的比较。其他算法可能要求元素类型支持<运算符
  3. 算法永远不会改变底层容器的大小,算法可能改变容器中保存元素的值,也可能在容器内移动元素,但是永远不会直接添加或删除元素。标准库定义了一类特殊的迭代器(插入器),当给这类迭代器赋值时,会在底层的容器上执行插入操作,算法可以操作这样一个迭代器实现容器中添加元素的效果,但是算法本身永远不会做这样的操作。
// 核心算法
auto result = find(vec.cbegin(), vec.cend(), val); // 如果存在此元素,则返回指向该元素的迭代器

10.2 初识泛型算法

  1. 大多数算法遍历输入范围的方式都相似,但他们使用范围中元素的方式不同。理解算法的最基本方法就是了解他们是否读取元素、改变元素或者是重排元素。

10.2.1 只读算法

  1. accumulate定义在头文件numeric中。第三个参数的和的初值。其第三个参数的类型决定了函数中使用那个加法运算符以及返回值的类型。序列中的元素类型必须与第三个参数匹配或者能转换为第三个参数的类型。
// 对vec中的元素求和,和的初值是0
int sum = accumulate(vec.cbegin(), vec.cend(), 0);
//string定义了+运算符
string sum = accumulate(vec.cbegin(), vec.cend(), string(""));
//错误:const char*上没有定义+运算符
string sum = accumulate(vec.cbegin(), vec.cend(), "");  
//注意使用cbegin和cend,因为不需要改变元素值
  1. equal算法,用于确定两个序列是否保存相同的值。前两个迭代器表示第一个序列的范围,第三个迭代器表示第二个序列的首元素。元素类型不必一样,只要能用==来比较两个元素类型即可。基于一个重要的假设,即第二个序列至少与第一个序列一样长。
// roster2 中的元素数目应该至少与roster1一样多
equal(roster1.cbegin(), roster1.cend(), roster2.cbegin());

10.2.2 写容器元素的算法

  1. fill算法,将给定值赋予输入序列的每一个元素
fill(vec.begin(), vec.end(),  10);  // 将每个元素重置为10
  1. fill_n函数
fill_n(dext, n, val);  // 保证目标容器足够大
  1. 插入迭代器:当通过一个插入迭代器赋值时,一个与赋值号右侧值相等的元素被添加到容器中。
  2. back_inserter,是一个定义在头文件iterator中的一个函数,其接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器,当通过此迭代器赋值时,赋值运算符 会调用push_back将一个具有给定值的元素添加到容器中。
vector<int> vec;
auto it = back_inserter(vec);  //通过它赋值会将元素添加到vec中
*it =42;       // vec中现在有一个元素,值为42

fill_n(back_insetrer(vec), 10, 0);  // 添加10个元素到vec
  1. 拷贝算法:必须保证第二个序列的元素个数至少等于第一个序列
int a1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int a2[sizeof(a1)/sizeof(*a1)];
// ret指向拷贝到a2的尾与元素之后的位置
auto ret = copy(begin(a1), end(a2), a2);
  1. replace算法,将所有给定值的元素都改为另一个值。此算法接受一个额外的迭代器,调用后,原序列保持不变,ivec包含list的一份拷贝,不过原来list中0的元素改为42
// 将所有值为0的元素改为42
replace(list.begin(), list.end(), 0, 42);
// 此算法接受一个额外的迭代器
replace(list.begin(), list.end(), back_inserter(ivec), 0, 42);

10.2.3 重排容器元素的算法

  1. 消除重复元素
void elimDups(vector<string> &words){
	sort(words.begin(). words.end());
	// unique重排输入范围,使得每个单词只出现一次
	// 排列在范围前部的,返回指向不重复区域之后的一个位置的迭代器
	auto end_unique = unique(words.begin(), words.end());
	// 使用向量操作erase删除重复元素
	words.erase(end_unique, word.end());
}
  1. 标准库算法对迭代器而不是容器进行操作,因此,算法不能直接添加或删除元素

10.3 定制操作

10.3.1 向算法传递函数

  1. sort函数接受第三个参数,此参数是一个谓词。谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。谓词可以分为一元谓词(只接受一个参数)和二元谓词(有两个参数),元素类型必须能转换为谓词的参数类型。
// 比较函数,用来按长度排序单词
bool isShorter(const string &s1, const string &s2){
	return s1.size() < s2.size();
}
sort(words.begin(), words.end(), isShorter);
  1. stable_sort函数:长度相同按字典序进行排序

10.3.2 lambda表达式

  1. 一个lambda表达式表示一个可调用的代码单元。可以在函数体内部。
  2. lambda只有在其捕获一个它所在函数中的局部变量,才能在函数体内使用该变量
void biggies(vector<string> &words, vector<string>::size_type sz){
	elimDups(words);  // 删除重复元素
	stable_sort(words.begin(), words.end(), isShorter);   // 按长度排序,长度相同的单词维持字典序
	// 获取迭代器,返回第一个满足size() >= sz的元素
	auto wc = find_if(words.begin(), words.end(),
					[sz] (const string &a) {return a.size >= sz;});
	for_each(wc, words.end(), [] (const string &s){cout << s << " "});
	cout << endl;
}
  1. 捕获列表只用于局部非static变量,lamdba可以直接使用局部static变量和在它所在函数之外声明的名字。

10.3.3 lambda捕获和返回

10.3.4 参数绑定

10.4 再探迭代器

10.4.1 插入迭代器

10.4.2 iostream迭代器

10.4.3 反向迭代器

10.5 泛型算法结构

10.5.1 5类迭代器

10.5.2 算法形参模式

10.5.3 算法命名规范

10.6 特定容器算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值