1 概述
标准库没有给每个容器提供大量的功能,而是提供了一组算法,这些算法大部分独立于特定的容器。这些算法是通用的:他们可以用于不同类型的容器和不同类型的元素。
泛型算法:一些经典算法的公共接口,用于不同类型元素、多种容器类型的排序、搜索。
头文件:algorithm
这些算法一般,遍历由两个迭代器指定的一个元素范围来操作:
auto result = find(vec.cbegin(),vec.cend(),42);
算法不会影响容器的大小,不会删除、添加元素,及算法不能执行容器操作;
2 初识泛型算法
2.1 accumulate()求和:
计算两个迭代器之间元素的和,第三个参数是初始值;定义的“+”运算的类型,都可以使用accumulate函数;
//算术求和
vector <int> venc;
int sum = accumulate(venc.cbedin(),venc.cend(),0);
//连接字符串
vector <string> v;
string sum = accumulate<v.cbegin(),v.cend(),string(" ") );
2.2 equal() 求等长类型相等否
equal(roster1.cbegin(), roster1.cend(),roster2.cbegin() );
roster1.cbegin(), roster1.cend(): 表示一个序列;
roster2.cbegin():第二个序列的首元素;
注意:
1 两个序列类型可以不一样,只要能用 == 比较就行;
2 算法假设两个序列一样长,在第二个序列中取出相同长度和一序列比较;
2.3 fill() 、fill_n()写容器
fill(venc.begin(),venc.end(),0 ); //将迭代器范围的值设为0;
fill_n(venc.begin(),venc.size(),0) //所有元素重置为0;
fill_n(dest.begin(), n ,val) //dest的前n个重置为cal;
2.4 copy()拷贝算法
2.5 replace()替换序列某元素
replace(ilst.begin(),ilst.end(),0,42); //将所有的 0 改为 42;
2.6 replace_copy()拷贝替换
2.7 sort()排序
sort(word.begin(),word.end()):范围内从小到大排序;
unique(word.begin(),word.end()):一般用于sort排序后的序列,将重复的元素排在后面,返回第一个重复元素所在位置;
sort(histVector.begin(), histVector.end(), greater<float>());
上述例子中系统自己为sort提供了less仿函数。在STL中还提供了其他仿函数,以下是仿函数列表:
equal_to
相等
not_equal_to
不相等
less
小于
greater
大于
less_equal
小于等于
greater_equal
大于等于
3 定制操作
标准库,允许我们提供资金定义的操作;如sort()的方向排序;
3.1 向算法传递函数
sort的重载版本有第三个参数,其是谓词(只接受一个或者两个参数)
按照长度从短到长排序words
sort(words.begin(),words.end(),isShorter);
stable_wort(words.begin(),words.end(),isShorter); //长度从短到长,相等大小的,按字母表顺序排;
elimDup(words); //将words按字典排序,删除重复单词;
//用partition()函数,第三个谓词参数为真的排在前面,为假的排在后面,返回第一个为假的
#include <iostream> #include <string> #include <vector> #include <algorithm> //! Predicate inline bool isLongerThan5(const std::string &s) { return s.size() >= 5; } void partition_words(std::vector<std::string> &v) { auto iter_longerLast = std::partition(v.begin(), v.end(), isLongerThan5); //! @note the range to be printed not whole of the v, so can't use for range. for(auto it = v.begin(); it != iter_longerLast; ++it) std::cout << *it << " "; std::cout << std::endl; } int main() { std::vector<std::string> v{"a","as","aasss","aaaaassaa","aaaaaabba","aaa"}; partition_words(v); return 0; }
3.2 lambda 表达式
可调用对象有:函数、指针、重载了函数调用运算符的类、lambda表达式;
lambda表达式,表示一个可调用的代码单元。
与任何函数类似,一个lambda具有一个返回类型、一个参数列表、一个函数体;
lambda可能定义在函数内部;
- [captures] (params) -> ret {Statments;}
![]()
注释:[capturne]方括号中的数是另外包含进去的可使用的数;
//sort()排序、enique()再排序、vs.erase()删除重复、stable_sort()大小字幕表排序、find_if()找到第一个大小为3的、for_each打印每个大于等于三的;
auto wc = std::find_if(vs.begin(), vs.end(),[sz](string const& s){ return s.size() >= sz; }); std::for_each(wc, vs.end(), [](const string &s){ std::cout << s << " "; });
//找出vector<strig> 中,所有size()大于3的字符串,并输出,不可重复;//
#include <iostream> #include <string> #include <vector> #include <algorithm> //! from ex 10.9 void elimdups(std::vector<std::string> &vs) { std::sort(vs.begin(), vs.end()); auto new_end = std::unique(vs.begin(),vs.end()); vs.erase(new_end, vs.end()); } //! ex10.18 void biggies_partition(std::vector<std::string> &vs, std::size_t sz) { elimdups(vs); auto pivot = partition(vs.begin(), vs.end(),[sz](const std::string &s){ return s.size() >= sz;} ); for(auto it = vs.cbegin(); it != pivot; ++it) std::cout << *it << " "; } //! ex10.19 void biggies_stable_partition(std::vector<std::string> &vs, std::size_t sz) { elimdups(vs); auto pivot = stable_partition(vs.begin(), vs.end(),[sz](const std::string& s){ return s.size() >= sz; }); for(auto it = vs.cbegin(); it != pivot; ++it) std::cout << *it << " "; } int main() { //! ex10.18 std::vector<std::string> v{ "the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle" }; std::cout << "ex10.18: "; std::vector<std::string> v1(v); biggies_partition(v1,4); std::cout << std::endl; //! ex10.19 std::cout << "ex10.19: "; std::vector<std::string> v2(v); biggies_stable_partition(v2,4); std::cout << std::endl; return 0; }
3.3 lambda值捕获:
#include <iostream> #include <string> #include <vector> #include <algorithm> using std::vector; using std::count_if; using std::string; //! Exercise 10.20 std::size_t bigerThan6(vector<string> const& v) { return count_if(v.cbegin(), v.cend(), [](string const& s){ return s.size() > 6; }); } int main() { //! ex10.20 vector<string> v{ "alan","moophy","1234567","1234567","1234567","1234567" }; std::cout << "ex10.20: " << bigerThan6(v) << std::endl; //! ex10.21 int i = 7; auto check_and_decrement = [&i](){ return --i ? false : true; }; std::cout << "ex10.21: "; while(!check_and_decrement()) std::cout << i << " "; std::cout << i << std::endl; return 0; } //! output : //! //ex10.20: 4 //ex10.21: 6 5 4 3 2 1 0
3.4 参数绑定
//统计长度大于等于6的个数
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <functional> using std::string; using namespace std::placeholders; bool isBiggerThan6(const string &s, string::size_type sz) { return s.size() > sz; } int main() { std::vector<string> authors{"Mooophy", "pezy", "Queequeg90", "shbling", "evan617"}; std::cout << count_if(authors.cbegin(), authors.cend(), bind(isBiggerThan6, _1, 6)); } // @Out // 4
4 再探迭代器
4.1 插入迭代器
std::unique_copy(vec.begin(), vec.end(), back_inserter(lst)); //无重复的拷贝;
4.2 iostream迭代器
4.2.1 istream_iterator迭代器
stream_iterator<int> in_iter(cin); //
stream_iterator<int> eof; //定义为空,从而可当作尾后迭代器来使用。
4.2.2 ostream_iterator
//读入一个文本,将其存入vector<string>中,并输出 #include <iostream> #include <fstream> #include <vector> #include <string> #include <iterator> using std::string; int main() { std::ifstream ifs("../data/book.txt"); std::istream_iterator<string> in(ifs), eof; std::vector<string> vec; std::copy(in, eof, back_inserter(vec)); // output std::copy(vec.cbegin(), vec.cend(), std::ostream_iterator<string>(std::cout, "\n")); }
//读入数列,并排序无重复输出 #include <iostream> #include <vector> #include <algorithm> #include <iterator> int main() { std::istream_iterator<int> in_iter(std::cin), eof; std::vector<int> vec; while (in_iter != eof) vec.push_back(*in_iter++); std::sort(vec.begin(), vec.end()); std::unique_copy(vec.cbegin(), vec.cend(), std::ostream_iterator<int>(std::cout, " ")); }
4.4 反向迭代器
//寻找并打印第一个单词 auto comma=find(line.begin(),line.end(),','); cout<<string(line.begin(),comma)<<endl; //选择并打印最后一个单词 auto rcomma=find(line.rbegin(),line.rend(),','); cout<<string(rcomma.base(),line.end());
//将v的3到7之间的数,逆序拷贝到I中; std::copy(v.crbegin() + 3, v.crbegin() + 8, std::back_inserter(l));