标准库算法都是对一个范围内的元素进行操作(除了少数例外)。并将此范围称为“输入范围”,而且总是使用前两个参数来表示次范围,这两个参数分别代表,要处理的首元素和尾元素之后位置的迭代器。
1.1、只读算法
只会读取输入范围内的元素,而从不改变元素
find
int sum = accumulate(c.begin(),c.end(),0);
string sum = accmulate(strc.begin(),strc.end(),string(""));
string sum = accmulate(strc.begin(),strc.end(),"");//错误
对于只读,不改变元素的算法,通常使用cbegin(),cend()
操作两个序列的算法
//c2的元素数目至少应该等于c1。
//
equal(c1.begin(),c1.end(),c2.begin());
1.2、写容器元素算法
算法不会执行容器操作,因此它们不可能改变容器大小。
fill(c.begin(),c.end(),0);//用0填充。
fill(c.begin(),c.size(),0);
//插入迭代器
//back_inserter
vector<int> vec;
auto it = back_inserter(vec);
*it = 42;
//常常用back_inserter创建一个迭代器
fill_n(back_inserter(vec),vec.size(),0);
拷贝算法
//copy
int a1[] = {1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1)/sizeof(*a1)];
auto ret = copy(begin(a1),end(a1),a2);
//replace replace(c.begin(),c.end(),0,5);//将序列c中的0替换为5
//replace_copy,不改变原来的序列
replace_copy(c.begin(),c.end,back_inserter(ivec),0,5);//ivec是c的拷贝。
1.3、排序算法
sort(c.begin(),c.end());//对列表c中的元素重新排序
auto end_unique = unique(c.begin(),c.end()); //消除重复元素
2.1、向算法传递函数
bool isShorter(const string &s1, const string &s2)
{
return si.size()< s2.size();
}
sort(c.begin(),c.end(),isSorter);
2.2、lambda表达式
一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。
[capture list](parameter list) -> return type{function bodt}
[捕获列表]为lambda所在函数中定义的局部变量的列表(通常为空)
(形参列表) 参数列表
return type 返回类型
function body 函数体
[](const string &s1,const string s2){return s1.size()<s2.size)()}
//可以忽略参数列表和返回类型,但必须包含捕获列表和函数体
auto f = []{return 42;};
隐式捕获
[=](const string &s1){return s.size() >= sz;};//=表示值捕获方式
[&](const string &s1){return s.size() >= sz;};//&引用捕获
//混合使用隐式捕获和显式捕获,&隐式捕获,引用捕获,c显式捕获,值捕获
[&,c](const string &s){os<<s<<c};
使用混合捕获方式时,捕获方式不能相同。即,隐式捕获为值捕获时,显式捕获必须为引用捕获方式。
可变lambda
size_t v1 = 42;
auto f= [v1]()mutable{return ++v1};
指定lambda返回类型
[](int i) -> int{if(i<0) return -i;else return i;};
2.3、参数绑定
bind函数
//arg_list是用逗号分隔的参数列表。对应给定的callable的参数。
auto newCallable = bind(callable, arg_list);
auto check6 = bind(check_size, _1,6);
string s = "hello";
bool b1 = check6(s);//调用check6(s)时会调用check_size(s,6);
使用placeholders名字
名字_n都定义在一个名为placeholders的命名空间中,这个命名空间本身定义在std命名空间中。为了使用这些名字,两个命名空间都要写上。bind、placeholders都定义在functional头文件中。
3.1、插入迭代器
back_inserter
front_inserter
inserter
3.2、iostream 迭代器
istream_iterator读取输入流
ostream_iterator输出流写数据
istream_iterator<int> int_it(cin); //从cin读取int
istream_iterator<int> eof; //尾后迭代器
vector<int> vec(int_it,eof);
vector<int>::iterator myiter;
for(myiter = vec.begin();myiter!=vec.end();myiter++)
{
cout << *myiter << endl;
}
注:eof被定义为空迭代器,对于一个绑定到流的迭代器,一旦其关联的流遇到文件尾或遇到IO错误,迭代器的值就与尾后迭代器相等。
//输出流操作
const char *str = {"hello"};
ostream_iterator<char> out_iter(cout,"\n");
for(int i = 0;i<5;i++)
{
out_iter = str[i];
}
3.3、反向迭代器
反向迭代器是在容器中从尾元素向首元素反向移动的迭代器。
在反向迭代器中递增递减操作的含义会跌倒过来。
递增一个反向迭代器(++it)会移动到前一个元素;递减一个反向迭代器会移动到一个元素。
//反向迭代器
int arr[] = {1,2,3,4,5,6,7};
size_t size = sizeof(arr)/sizeof(int);
vector<int> vet_int(arr,arr+size);
vector<int>::reverse_iterator iter;
for(iter = vet_int.rbegin();iter!=vet_int.rend();iter++)
{
cout << *iter << endl;
}
4.1、5类迭代器
算法所要求的迭代器操作可以分为5个迭代器类别
第二种算法分类方式是按照是否读、写或者重排序序列中的元素
4.2、算法形参模式
大多数算法具有如下4中形式
//alg算法名字
alg(beg,end,other args);
alg(beg,end,dest,other args);
alg(beg,end,beg2,other args);
alg(beg,end,beg2,end2,other args);
4.3、算法命名规范
一些算法使用重载形式传递一个谓词
unique(beg,end);//使用==运算符比较元素
unique(beg,end,compare);//使用compare比较
_if版本的算法
接受一个元素值的算法通常有一个不同名的版本,该版本接受一个谓词代替元素
find(beg,end,val);//查找范围内val第一次出现的位置
find(beg,end,pred);//查找第一个令pred为真的元素
//都是用来查找出现的位置
区分拷贝版和非拷贝版
reverse(beg,end);//不拷贝,只反转
reverse_copy(beg,end,dest);//逆序拷贝到dest
list, forward_list定义了独有的sort, merge, remove, reverse 和 unique。通用版本要求随机反问迭代器,因此不能用于list和forwar_list。
对于list和forward_list应该优先使用成员函数版本的算法而不是通用算法