泛型算法介绍
泛型算法大多数是独立于任何特定的容器的,定义在头文件algorithm
和numeric
中,算法不直接操作容器,而是遍历由两个迭代器指定的一个元素范围。
泛型算法种类
只读算法
find(vec.cbegin(),vec.cend(),0);//返回迭代器
count(vec.cbegin(),vec.cend(),0);//返回给定值在序列中出现的次数
int sum = accumulate(vec.cbegin(),vec.cend(),0);//sum设置为vec中元素的和,定义在numeric中,和的初值为0
string sum = accumulate(vec.cbegin(),vec.cend(),string(""));//string才有加法运算,char * 类型没有,字符串的初值为空
equal(roster1.cbegin(), roster1.cend(),roster2.cbegin());//可以用来比较不同容器内的元素,只要能用==比较就可以,第二个序列至少与第一个一样长!如果两个序列中的元素完全一样则相等。
写容器元素的算法
fill(vec.begin(), vec.end(), 0);//将每个元素重置为0,注意不能超出原有vec的size,否则会出错
fill_n(vec.begin(), vec.size(), 0);
auto ret = copy(begin(a1), end(a1), a2);//拷贝到新的数组中去,返回的是尾元素之后的位置
replace(list.begin(), list.end(), 0, 42);//把所有0的值取代为42
replace_copy(list.begin(), list.end(), back_inserter(vec), 0,42);//取代后拷贝到新的容器中
size是指出vector存有元素的个数,capacity是指出现有vector可以存放多少元素
插入迭代器
#include <iterator>
vector<int> vec;
auto it = back_inserter(vec);//返回一个插入迭代器
*it = 42;
*it = 50;
cout << vec.size() << endl;//结果为2,调用一次相当于一次push_back;
fill_n(back_inserter(vec), 10, 0);
cout << vec.size() << endl;//结果为12!
重排容器
删除序列中重复元素的程序:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
void elimDups(vector<string> & words) {
sort(words.begin(), words.end());//排序
auto end_unique = unique(words.begin(), words.end());//不重复元素出现在开始部分,返回不重复区域之后一个元素的迭代器
words.erase(end_unique, words.end());//删除掉多余的
}
int main() {
vector<string> vec;
vec.push_back("e");
vec.push_back("b");
vec.push_back("c");
vec.push_back("c");
vec.push_back("d");
vec.push_back("d");
vec.push_back("a");
elimDups(vec);
cout << vec.size() << endl;
return 0;
}
swap操作
操作于容器(除了array,string)迭代器,指针,引用仍指向原来元素值,操作于string会失效,操作于array迭代器,指针,引用指向原来元素位置但值改变啦!(303页)
swap(vec1,vec2);
定制操作
自定义函数,然后向算法传递参数取代原有的比较函数(如<运算符)
bool isshorter(const string & s1, const string & s2) {
return s1.size() < s2.size();
}
sort(words.begin(), words.end(), isshorter);
// 保证等长元素之间的字典序
stable_sort(words.begin(), words.end(), isshorter);
lambda表达式
lambda的目的是解决谓词参数过多的问题
可以忽略参数列表和返回类型,如果函数体只是一个return语句则可推断出返回类型,否则为void。因此必要时要使用尾置返回类型。lambda不能有默认参数。
捕获列表只用于局部非静态变量,可以直接使用局部静态变量和在它所在函数体之外声明的名字。
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
void elimDups(vector<string> & words) {
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());//返回不重复区域之后一个元素的迭代器
words.erase(end_unique, words.end());
}
void biggies(vector<string> words, int sz) {
elimDups(words);
stable_sort(words.begin(), words.end(), [](const string & s1, const string & s2) {
return s1.size() < s2.size();
});
auto wc = find_if(words.begin(), words.end(), [sz](const string & s) {
return s.size() >= sz;
});//find_if只接受一元谓词
for_each(wc, words.end(), [](const string & s) {
cout << s << " ";
});
}
int main() {
vector<string> vec;
vec.push_back("haa");
vec.push_back("dada");
vec.push_back("feifei");
vec.push_back("feifei");
vec.push_back("heihei");
vec.push_back("hi");
vec.push_back("leila");
biggies(vec, 5);
return 0;
}
lambda捕获
当定义一个lambda时即生成一个类和该类的一个对象,捕获参数为类对象的数据成员并在创建时被初始化。
捕获参数是在创建时被拷贝而不是调用时拷贝。因此捕获之后修改值不会影响lambda函数的执行。
当以引用方式捕获变量时必须保证lambda执行时变量是存在的,函数返回lambda时不能有一个局部变量的引用。尽量避免捕获指针或引用。
可以用=或&来隐式捕获,混用的话第一个必须是两者之一,后面的必须是单独指出的相反的那一个。
值捕获需要加mutable才能修改值,引用则不用
void fun() {
int a = 5;
auto f = [a]() mutable{ return ++a; };
cout << f() << endl; //6
cout << f() << endl; //7
}
参数绑定
也是用来解决谓词参数过多的问题。可以将bind看成一个通用的函数适配器。使用头文件functional
中包含的bind
函数,同时要使用命名空间using namespace std::placeholders
_n是占位符,表示调用绑定后函数传入的参数的位置。
bool check_size(const string & s, int sz) {
return s.size() >= sz;
}
auto wc = find_if(words.begin(), words.end(),bind(check_size, _1, sz));
绑定引用参数
for_each(words.begin(), words.end(), bind(print, ref(os), _1, ''));//cref保存const引用的类