10泛型算法
标准库并未给每个容器都添加大量功能,而是提供了一组标准算法,这些算法中的大多数都独立于任何特定的容器。这些算法是通用的(generic 或称为泛型的):它们可以用于不同类型的容器和不同类型的元素。
泛型算法(generic algorithm)之所以称为算法,是因为它们实现了一些经典算法的公共接口,如排序或搜索;称他们是泛型的,是因为它们可以用于不同类型的元素和多种容器类型。
三、lambda
调用运算符:如果可以对其使用调用运算符,则称一个对象是可以被调用的。 目前用过的可调用对象:函数和指针
[capture list](parameter list) ->return type {function body}
capture list(捕获列表)是一个lambda所在函数中定义的局部变量的列表(通常为空),其他与普通函数一样。lambda必须使用尾置返回来指定返回类型。
lambda不能有默认参数,所以lambda调用的实参数目必须与形参数目相等。
[](const string &a,const string b) {return a.sie() < b.size();}
空捕获列表表明lambda不使用它所在函数中的任何局部变量。
stable_sort(words.begin(),words.end(), [](const string &a,const string b){return a.sie() < b.size();));
当stable_sort需要比较两个元素时,它就会调用lambda表达式。
lambda通过将局部变量包含在其捕获列表中,来指出将会使用这些变量。一个lambda只有在其捕获列表中捕获一个它所在函数中的局部变量,才能在函数中使用该变量。
[sz](const string &a) {return a.size() >= sz;} auto wc = find_if(words.begin(),words.end(),[sz](const string &a){return a.size() >= sz});
指向第一个长度大于给定参数sz的元素。如果不存在,则返回words.end()的一个拷贝。
例 1.接受两个int,返回它们的和。
auto sum = [](int a,int b) {return a + b};
2.捕获所在函数的int,并接受一个int参数。返回捕获int和int参数的和。
void add(int a){ auto sum =[a](int b ) {return a + b }; }
3.1 lambda捕获与返回
当向函数传递一个lambda时,同时定义了一个新类型与该类型的对象:传递的参数就是此编译器生成的类类型的未命名对象。
类似参数传递,变量的捕获方式也可以是值或者引用。
值捕获:在lambda创建时就拷贝v1的值,后面v1的值改变不影响值捕获的变量。 引用捕获:在lambda函数体内使用此变量时,实际上使用的是引用所绑定的对象。 当以引用方式捕获一个变量时,必须保证在lambda执行时变量时存在的。
混合使用显式捕获和隐式捕获:
&告诉编译器捕获引用方式; =告诉编译器采用值捕获方丝滑。
可变lambda
对于值捕获,参数列表加上:mutabl
auto f =[v1] () mutable {return ++v1};
一个引用捕获的变量能否修改取决于引用指向的变量时const 还是非const类型。
指定lambda返回类型
当需要为lambda指定返回类型时,必须使用尾置类型。
[](int i) -> int {if (i < 0) return -i; else return i;}
四、迭代器
插入迭代器
标准库算法为了保证通用性,并不直接操作容器,而是通过迭代器来访问容器元素,算法不具备直接向容器插入元素的能力,而插入器正式帮助算法实现向容器插入元素的能力。有三种类型,区别在于元素插入位置不同。
- back_inserter
- 原理:创建一个使用push_back的迭代器。调用push_back.
- 功能:在容器的尾端插入元素。
- 限制:只有提供了push_back()成员函数的容器中,back_inserter才能派上用场。
- 适用:vector deque lis
- front_inserter:
- 原理:创建一个使用push_front的迭代器。调用push_front.
- 功能:在容器前端插入元素
- 限制:只有提供了push_front()成员函数的容器中,form_Inserter才能派上用场。
- 适用:deque list
- inserter:
- 原理:创建一个使用insert的迭代器。此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器。元素将被插入到给定迭代器所表示的元素之前。
- 功能:在容器的指定位置插入元素。
- 限制:只有提供了inset()成员函数的容器中,inserter才能派上用场,所有STL容器都提供了inset()函数。
- 适用:所有STL容器。
iostream迭代器
通过流迭代器,我们可以用泛型算法从流对象读取数据以及向其写入数据。
istream_iterator:读取输入流
ostream_iterator:向一个输出流写数据。
istream_iterator<int> in_iter(cin);//从cin读取int istream_iterator<int>eof; //isteram尾后迭代器 while(in_iter != eof) vec.push_back(*in_iter++);
对于一个绑定到流的迭代器,一旦关联的流遇到文件尾或遇到IO错误,迭代器的值就与尾后迭代器相等。
ostream_iterator
ostream_iterator(T) out(os); //out将类型为T的值写入到输出流os中 ostream_iterator(T) out(os,d)//out将类型为T值写入到输出流os中,每个值后面都输出一个d,d指向一个空字符结尾的字符数组。
void change(vector<int>&vec) { ostream_iterator<int> out_iter(cout, "danliu"); for (auto e : vec) *out_iter++ = e; //赋值语句将e写入到cout cout << endl; }
以下代码也能用来打印容器
ostream_iterator<int>out_iter(cout," "); copy(vec.begin(),vec.end(),outiter);
五、泛型算法结构
算法要求的迭代器操作可以分为5个迭代器类别(iterator category),每个算法都会对它的每个迭代器参数指明需要提供哪类迭代器。
- Input iterator(输入迭代器):只读,不写,单遍扫描,只能递增;
- Output iterator(输出迭代器):只写,不读,单遍扫描,只能递增;
- Forward iterator (前向迭代器):可读写,多遍扫描,只能递增;
- Bidirectional iterator(双向迭代器):可读写,多遍扫描,可递增递减;
- Random Access iterator(随机访问迭代器):可读写,多遍扫描,支持全部迭代器运算;