Chapter10:泛型算法
泛型算法的基础是迭代器。
迭代器令算法不依赖于容器,但是算法依赖于元素类型的操作。也即:算法永远不会执行容器的操作。
那么,如果想向容器中添加元素或者执行其他的一些操作呢?标准库提供了插入迭代器来完成。但算法自身永远不会做这样的操作。
- 理解算法最基本的方法是:了解它们是否读取元素、改变元素、或是重排元素。
只读算法
int sum = accumulate(vec.cbegin(), vec.cend(),);
//第三个参数类型决定了函数中使用哪个加法运算符及返回值类型
这里面蕴含着一个编程假定:将元素类型加到和的类型上的操作是可行的。
string sum = accumulate(v.cbegin(), v.cend(), string(""));
//错误:string无法转换为const char*
string sum = accumulate(v.cbegin(), v.cend(), "");
Best Practice:对于只读算法,最好使用cbegin()和cend()。
写算法
算法不会执行检查操作,不会检查写算法。
重排容器的算法
//消除重复单词
void elimDups(vector<string> &words)
{
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());//使用容器操作来删除元素
}
- 定制操作——谓词
谓词是一个可调用表达式,其返回一个能用作条件的值。到目前为止,我们仅用过两种可调用对象:函数和函数指针。还有其他两种可调用对象:重载了函数调用运算符的类和lambda表达式。
lambda表达式:
具有一个返回类型、一个参数列表、一个函数体。
[capture list] (parameter list) -> return type {function body}
表达式格式说明:
「我们可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体。
忽略参数列表,等价于一个空参数列表;忽略返回类型,如果函数体只有一个return语句,则从返回的表达式推断函数类型,否则,返回类型为void。
虽然一个lambda可以出现在一个函数中,使用其局部变量,但它只能使用那些明确指明的变量。
一个lambda可以直接使用定义在当前函数之外的名字。即:捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和在它所在函数之外声明的名字。」
void biggies(vector<string> &words, vector<string>::size_type sz)
{
elimDups(words);
//按长度稳定排序
stable_sort(words.begin(), words.end(), [](const string& a, const string& b) {return a.size() < b.size(); });
//获取第一个size大于sz的元素
auto wc = find_if(words.begin(), words.end(), [sz](const string &a) {return a.size() >= sz; });
//size大于sz的元素数目
auto count = words.end() - wc;
cout << count;
//打印这些单词
for_each(wc, words.end(), [](const string &s) {cout << s << " "; });
cout << endl;
}
当定义一个lambda时,编译器生成一个与lambda对应的新的(未命名的)类类型。当向一个函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象:传递的参数就是此未命名对象。
捕获分为值捕获和引用捕获:
被捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝;
如果lambda可能在函数结束后执行,捕获的引用指向的局部变量已经消失;
确保lambda每次执行的时候,信息都有预期的意义,是程序员的责任;一般来说,我们应该尽量减少捕获的数据量,来避免潜在的捕获导致的问题,而且,如果可能的话,应该避免捕获指针和引用。
捕获分为隐式捕获和显式捕获。
如果混合使用隐式捕获和显式捕获,显式捕获必须使用与隐式捕获不同的方式:如果隐式捕获使用引用方式(&),则显示捕获使用值方式;反之亦然。
可变lambda:
如果我们希望能改变一个被捕获的变量的值,就必须在参数列表首加上关键字mutable。
对于那种只在一两个地方使用的简单操作,lambda表达式是最有用的;如果我们需要在很多地方使用相同的操作,通常应该定义一个函数,而不是多次编写相同的lambda表达式。
- 参数绑定
如果lambda的捕获列表为空,可以用函数来替代它。但是,对于捕获局部变量的lambda,用函数来替换它就不是那么容易了。我们必须解决这一问题。
auto newCallable = bind(callable, arg_list);
bool check_size(const string &s, string::size_type sz)
{
return s.size() >= sz;
} auto check6 = bind(check_size, placeholders::_1, );
以check6为例:只有一个占位符:表示check6只接受一个参数。占位符出现在arg_list的第一个位置,表示check6此参数对应到check_size的第一个参数。
最后一个问题:
for_each(words.begin(), words.end(), bind(print, os, _1, ' '));//错误,os不能拷贝
for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));
其他迭代器:流迭代器、插入迭代器、反向迭代器、移动迭代器。
算法形参的4种模式:
alg(beg, end, other args);
alg(beg, end, dest, other args);
alg(beg, end, beg2, other args);
alg(beg, end, beg2, end2, other args);
list和forward_list使用自己的算法会比较好。
Chapter10:泛型算法的更多相关文章
- Chapter10(泛型算法)--C++Prime笔记
关键:算法通过在迭代器上进行操作来实现类型无关.算法不改变所操作序列的大小. 1.算法大多都定义在algorithm头文件中,标准库还在头文件numeric中定义了一组数值泛型算法. 2.泛型算法永远 ...
- C++ 泛型算法
<C++ Primer 4th>读书笔记 标准容器(the standard container)定义了很少的操作.标准库并没有为每种容器类型都定义实现这些操作的成员函数,而是定义了一组泛 ...
- C++的那些事:容器和泛型算法
一.顺序容器 1,标准库定义了3种类型的顺序容器:vector.list和deque.它们的差别主要在于访问元素的方式,以及添加或删除元素相关操作运算代价.标准库还提供了三种容器适配器:stack.q ...
- C++ Primer : 第十章 : 泛型算法 之 只读、写和排序算法
大多数算法都定义在<algorithm>头文件里,而标准库还在头文件<numeric>里定义了一组数值泛型算法,比如accumulate. ● find算法,算法接受一对迭代 ...
- 【STL】帮你复习STL泛型算法 一
STL泛型算法 #include <iostream> #include <vector> #include <algorithm> #include <it ...
- C++ Primer 5th 第10章 泛型算法
练习10.1:头文件algorithm中定义了一个名为count的函数,它类似find,接受一对迭代器和一个值作为参数.count返回给定值在序列中出现的次数.编写程序,读取int序列存入vector ...
- C++标准库之泛型算法
本文中算法都是指泛型算法. 基本要点: 1)算法使用迭代器进行操作. 2)不依赖容器,但容器希望使用算法,就必须提供接口. 3)通用算法永远不会执行容器操作.操作仅指:更改容器大小的操作.但,容器内部 ...
- C++ Primer 读书笔记:第11章 泛型算法
第11章 泛型算法 1.概述 泛型算法依赖于迭代器,而不是依赖容器,需要指定作用的区间,即[开始,结束),表示的区间,如上所示 此外还需要元素是可比的,如果元素本身是不可比的,那么可以自己定义比较函数 ...
- STL的一些泛型算法
源地址:http://blog.csdn.net/byijie/article/details/8142859 从福州大学资料里摘下来的我现在能理解的泛型算法 algorithm min(a,b) 返 ...
随机推荐
- Sails 关闭自动路由 Automatic Routes 功能。
Sails 关闭自动路由 Automatic Routes 功能. Sails 中的路由两种:Custom Routes 和 Automatic Routes,自定义路由和自动路由.详见文档: Sai ...
- 使用C#开发ActiveX控件(新) 转 http://www.cnblogs.com/yilin/p/csharp-activex.html
前言 ActiveX控件以前也叫做OLE控件,它是微软IE支持的一种软件组件或对象,可以将其插入到Web页面中,实现在浏览器端执行动态程序功能,以增强浏览器端的动态处理能力.通常ActiveX控件都是 ...
- JSP 中的几种注释
1.多行注释 <!-- 注释1 注释2 注释3 --> 或者 <!-- 注释1 …… 注释n //--> 2.多行注释,不同的是:注释内容不会发送到客户端,会被JSP引擎所忽略 ...
- 石阶 VS 石像
山庙有尊雕刻精美的佛像,前来拜佛的人络绎不绝. 铺在山路上的石阶开始抱怨:“大家同是石头,凭什么我被人蹬来踩去,你却被人供在殿堂?” 佛像笑了笑:“当年你只挨六刀,做了一方石阶,而我经历了千刀万凿之后 ...
- 第五篇 Getting Started with ORACLE EBS(开始学习ORACLE EBS)
第一篇介绍了ERP软件是供应链管理软件.告诉你这个软件改善或提升企业管理的切入点和着力点.有了着力点才能给力. 第二篇介绍了什么是咨询以及咨询工作共通的章法,告诉了你咨询的套路是什么,就像练习一套拳, ...
- MDM平台学习笔记
最近和将来一段时间都会花很多时间在主数据管理平台的学习和开发上,从现在开始打算记录此过程中的知识点和学习心得,加油! 1.IBM全新的产品文档网站IBM Knowledge Center,软件硬件产品 ...
- 浅析JavaScript引用类型之--Object、Array
1.Object类型 对象是某个特定引用类型的实例,新对象有两种创建方式: i.使用new操作符调用构造函数来创建. var person = new Object(); person.name = ...
- NHibernate 二级缓冲
session.CreateCriteria(typeof(SysModuleFields)).SetCacheable(true).List<SysModuleFields>(); se ...
- bzoj4026
直接按照欧拉函数的计算方式来即可 φ=区间积*区间出现(质数-1)的积/区间出现过的质数的积 区间积是满足类似区间减法的操作的(利用逆元) 由于强制在线,上主席树就可以了(维护每个质数上次出现的位置p ...
- kafka_2.9.2-0.8.1.1分布式集群搭建代码开发实例
准备3台虚拟机, 系统是RHEL64服务版. 1) 每台机器配置如下:$ cat /etc/hosts # zookeeper hostnames: 192.168.8.182 ...