1、泛型算法本身不会执行容器的操作,只会运行于迭代器之上,执行迭代器的操作。算法永远不会改变底层容器的大小。
2、只读算法:一些算法只会读取其输入范围内的元素,从不改变元素。 对于只读算法,最好使用次cbegin()和cend()。
find:接受三个参数,前两个指出查找的元素的范围,第三个参数是要查找的元素。返回指向要查找元素的迭代器,若没找到指定元素,返回尾后迭代器。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
vector<int> vec = { 27, 210, 12, 47, 109, 83 };
int val = 83;
auto result = find(vec.cbegin(), vec.cend(), val);
cout << *result << endl; //输出83
system("pause");
return 0;
}
accumulate:接受三个参数,前两个指出需要求和的元素的范围,第三个参数是和的初值。返回求和的结果。
#include<iostream>
#include<algorithm>
#include<numeric>
#include<vector>
#include<string>
using namespace std;
int main(){
vector<int> vec{ 1, 2, 3, 4 };
int val = 0;
auto result = accumulate(vec.cbegin(), vec.cend(), val);
cout << result << endl; //输出10
//string定义了+运算符,能用accumulate函数将string元素连接起来
vector<string> svec{ "aaa", "bbb", "vvv" };
auto sresult = accumulate(svec.cbegin(), svec.cend(), string(""));
cout << sresult << endl; //输出aaabbbvvv
system("pause");
return 0;
}
equal:接受三个参数,前两个指出第一个序列中的元素范围,第三个参数表示指向第二个序列首元素的迭代器。判断两个序列是否保存相同的值。假定第二个序列至少与第一个序列一样长。
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
using namespace std;
int main(){
vector<int> vec{ 1, 2, 3, 4 };
list<int> li{ 1, 2, 3, 4 };
cout << equal(vec.begin(), vec.end(), li.begin()) << endl; //输出1
cout << equal(vec.begin() + 1, vec.end(), li.begin()) << endl; //输出0
system("pause");
return 0;
}
3、 写容器元素算法:必须确保序列原大小不小于要求写入的元素数目。
fill:接受三个参数,前两个指出序列中的元素范围,第三个参数表示将这个值赋予序列中的每个元素。
fill_n:接受一个单迭代器、一个计数值和一个值。将给定值赋予迭代器指向的元素开始的指定个元素。
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
vector<int> vec{ 1, 2, 3, 4 };
fill(vec.begin(), vec.begin() + vec.size() / 2, 0);
for (const auto& c : vec)
cout << c << " ";
cout << endl; //输出0 0 3 4
//向目的位置迭代器写入数据的算法假定目的位置足够大,能容纳要写入的元素
fill_n(vec.begin(), 3, 1);
for (const auto& c : vec)
cout << c << " ";
cout << endl; //输出1 1 1 4
system("pause");
return 0;
}
back_inserter:接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。
#include<iostream>
#include<algorithm>
#include<vector>
#include<iterator>
using namespace std;
int main(){
vector<int> vec;
fill_n(back_inserter(vec),5,0);
for(const auto& c:vec)
cout<<c<<" ";
cout<<endl; //输出0 0 0 0 0
system("pause");
return 0;
}
4、 拷贝算法
copy:接受三个迭代器,前两个表示输入范围,第三个表示目的序列的起始位置。把输入范围中的元素拷贝到目的序列中。
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int ia1[]={1,2,3,4};
int ia2[sizeof(ia1)/sizeof(*ia1)];
auto ret=copy(begin(ia1),end(ia1),ia2);//ret指向拷贝到ia2的尾元素之后的位置
for(const auto& i:ia2)
cout<<i<<" ";
cout<<endl; //输出1 2 3 4
system("pause");
return 0;
}
5、 重排容器元素算法
sort:接受两个迭代器,表示排序的元素范围
unique:将相邻的重复项“消除”,并返回一个指向不重复值范围末尾的迭代器。此位置之后的元素仍存在,但不知道值是什么。
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<vector>
using namespace std;
int main(){
string str="the quuick red fox jumps over the slow red turtle";
stringstream ss(str);
string word;
vector<string> vec;
while(ss>>word)
vec.push_back(word);
sort(vec.begin(),vec.end());
for(const auto& i:vec)
cout<<i<<" ";
cout<<endl; //输出fox jumps over quuick red slow the the turtle
auto end_unique=unique(vec.begin(),vec.end());
vec.erase(end_unique,vec.end());
for(const auto& i:vec)
cout<<i<<" ";
cout<<endl; //输出fox jumps over quuick red slow the turtle
system("pause");
return 0;
}
6、谓词是一个可调用的表达式,返回结果是能用作条件的值。谓词分一元谓词和二元谓词。
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<vector>
using namespace std;
//二元谓词,比较函数,按长度排序单词
bool isShorter(const string& s1,const string& s2){
return s1.size()<s2.size();
}
int main(){
string str="the quuick red fox jumps over the slow red turtle";
stringstream ss(str);
string word;
vector<string> vec;
while(ss>>word)
vec.push_back(word);
vector<string> vec2(vec);
sort(vec.begin(),vec.end(),isShorter);//按长度由短至长排序
for(const auto& i:vec)
cout<<i<<" ";
cout<<endl; //输出the red fox the red over slow jumps quick turtle
system("pause");
return 0;
}
7、lambda表达式具有如下形式
[capture list](parameter list) -> return type { function body }
capture list(捕获列表)是一个lambda所在函数中定义的局部变量的列表(通常为空)。return type、parameter list和function body分别表示返回类型(必须是尾置返回类型)、参数列表和函数体。可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体。
与上面isShorter函数完成相同功能的lambda:
[](const string& s1,const string& s2){ return s1.size()<s2.size(); }
lambda值捕获
void fun1(){
size_t v1=42;
auto f=[v1]{ return v1; };
v1=0;
auto j=f(); //j为42,f保存了我们创建它时v1的拷贝
}
lambda引用捕获
void fun2(){
size_t v1=42;
auto f=[&v1]{ return v1; };
v1=0;
auto j=f(); //j为0,f保存了v1的引用
}
lambda隐式捕获:&采用引用捕获方式,=采用值捕获方式
[=](const string& s1,const string& s2){ return s1.size()>=size; }
可变lambda:在参数列表首加上关键字mutable,改变被捕获变量的值
void fun3(){
size_t v1=42;
auto f=[v1] () mutable { return v1; };
v1=0;
auto j=f(); //j为43
}
8、 参数绑定
bind函数在头文件functional中,调用bind函数的一般形式为:
auto newCallable=bind(callable,arg_list);
newCallable本身是一个可调用的对象,arg_list是一个逗号分割的参数列表,对应给定callable的参数。
arg_list可能包含形如_n的名字,n是一个整数,这些参数是占位符,表示了newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置。_n定义在一个名为placeholders的命名空间中。
bind拷贝其参数,当希望传递给bind一个对象又不拷贝它,必须使用ref函数。
#include<iostream>
#include<functional>
using namespace std;
using namespace std::placeholders;
int add(int a,int b,int c,int d){
return a+b+c+d;
}
int main(){
int a=1,c=2;
auto g=bind(add,a,_2,c,_1);
cout<<g(3,4)<<endl; //调用add(1,4,2,3);
system("pause");
return 0;
}
9、 插入迭代器
back_inserter 创建一个使用push_back的迭代器 。
front_inserter 创建一个使用push_front的迭代器。
inserter创建一个使用insert的迭代器,此函数接受两个参数,这个参数必须是指向给定容器的迭代器。元素将被插入到给定迭代器所表示的元素之前。
#include<iostream>
#include<list>
#include<iterator>
using namespace std;
int main(){
list<int> lst{ 1, 2, 3, 4 };
list<int> lst2, lst3, lst4;
copy(lst.cbegin(), lst.cend(), back_inserter(lst2));
for (const auto& l : lst2)
cout << l << " ";
cout << endl; //输出1 2 3 4
copy(lst.cbegin(), lst.cend(), front_inserter(lst3));
for (const auto& l : lst3)
cout << l << " ";
cout << endl; //输出4 3 2 1
copy(lst.cbegin(), lst.cend(), inserter(lst4, lst4.begin()));
for (const auto& l : lst4)
cout << l << " ";
cout << endl; //输出1 2 3 4
system("pause");
return 0;
}
10、iostream迭代器
istream_iterator迭代器:读取输入流
ostream_iterator迭代器:向输出流写数据
#include<iostream>
#include<list>
#include<iterator>
using namespace std;
int main(){
list<int> lst;
istream_iterator<int> in(cin),eof;
while(in!=eof)
lst.push_back(*in++);//解引用迭代器,获得从流读取的前一个值
ostream_iterator<int> out(cout," ");
for(const auto& l:lst)
*out++=l; //将元素写到cout
cout<<endl;
system("pause");
return 0;
}
11、反向迭代器
反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。对于反向迭代器,++iter会移动到前一个元素,--iter会移动到下一个元素。除了forward_list之外,其他的容器都定义了反向迭代器。
下图显示了一个名为vec的vector上的4种迭代器:
#include<iostream>
#include<string>
#include<iterator>
#include<algorithm>
using namespace std;
int main(){
string str="FIRST,MIDDLE,LAST";
auto comma=find(str.cbegin(),str.cend(),',');
cout<<string(str.cbegin(),comma)<<endl; //输出FIRST
auto rcomma=find(str.crbegin(),str.crend(),',');
cout<<string(rcomma.base(),str.cend())<<endl;//输出LAST
system("pause");
return 0;
}
用图表示上面各个迭代器:
12、迭代器类别
输入迭代器:只读,不写,单遍扫描,只能递增
输出迭代器:只写,不读,单遍扫描,只能递增
前向迭代器:可以读写,多遍扫描,只能向前
双向迭代器:可以读写,多遍扫描,可以递增递减
随机访问迭代器:可读写,多遍扫描,支持全部迭代器运算。
13、 list 和 forward_list 的特定算法链表可以改变元素间的链接而不是真的交换它们的值来“交换”元素,因此特定算法的性能比对应的通用版本好很多。
#include<iostream>
#include<list>
using namespace std;
int main(){
list<int> lst1,lst2;
for(size_t i=1;i!=5;++i)
lst1.push_back(i);
for(size_t i=6;i!=10;++i)
lst1.push_back(i);
lst1.merge(lst2); //将lst2的元素合并入lst1,并将元素从lst2删除,lst1和lst2必须有序
for(const auto l:lst2)
cout<<l<<" ";
cout<<endl;
lst1.remove(5); //将lst1的指定元素删除
lst1.reverse(); //将lst1的元素反转
for(const auto l:lst1)
cout<<l<<" ";
cout<<endl;
list<int> lst3;
for(size_t i=20;i!=25;++i)
lst3.push_back(i);
lst1.splice(lst1.begin(),lst3);//将lst3中的所有元素移动到lst1.begin()之前的位置,并将元素从lst3删除
for(const auto l:lst1)
cout<<l<<" ";
cout<<endl;
system("pause");
return 0;
}