【c++ primer读书笔记】【第10章】泛型算法
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; }
posted on 2015-03-27 13:23 ruan875417 阅读(142) 评论(0) 编辑 收藏 举报