算法
一、函数对象
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载()
运算符,使得类对象可以像函数那样调用。
注意:
函数对象(仿函数)是一个类,不是一个函数
函数对象(仿函数)重载了()
运算符,使得它可以像函数一样调用。
分类:
假定某个类有一个重载的operator()
,而且重载的operator()
要求获取一个参数,我们就将这个类称为“一元仿函数(unary functor)”;类似地,如果重载的operator()
要求获取两个参数,就将这个类称为“二元仿函数(binary functor)”
函数对象的作用主要是什么?
STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略。
总结:
函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时问题。
函数对象超出了普通函数的概念,函数对象可以有自己的状态(因为类可以用自己的成员)
函数对象可内联编译,性能好。用函数指针几乎不可能
模板函数对象使函数对象具有通用性,这也是它的优势之一。
二、谓词
谓词是指普通函数或重载的operator()
返回值是bool
类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词;如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式。
即返回值类型是bool
类型的普通函数或仿函数,就叫谓词。
案例: 一元谓词
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 bool greaterThan20 (int val) { return val > 20 ; } class greaterThan20A {public : bool operator () (int val) { return val > 20 ; } }; void test05 () { vector<int > v; v.push_back (10 ); v.push_back (20 ); v.push_back (30 ); v.push_back (40 ); for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; vector<int >::iterator ret; ret = find_if (v.begin (),v.end (),greaterThan20); if (ret == v.end ()){ cout<<"没有查到" <<endl; }else { cout<<"第一个大于20的数为:" <<*ret<<endl; } cout<<"****************" <<endl; ret = find_if (v.begin (),v.end (),greaterThan20A ()); if (ret == v.end ()){ cout<<"没有查到" <<endl; }else { cout<<"第一个大于20的数为:" <<*ret<<endl; } }
运行结果:
案例: 二元谓词
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 bool myGreater1 (int v1,int v2) { return v1 > v2; } class myGreater2 {public : bool operator () (int v1,int v2) { return v1 > v2; } }; void test06 () { vector<int > v; v.push_back (10 ); v.push_back (30 ); v.push_back (15 ); v.push_back (40 ); for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; sort (v.begin (),v.end ()); cout<<"默认从小到大:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; sort (v.begin (),v.end (),myGreater1); cout<<"普通函数作为二元谓词 从大到小:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; sort (v.begin (),v.end (),myGreater2 ()); cout<<"函数对象作为二元谓词 从大到小:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; }
运行结果:
三、内建函数对象
STL内建了一些函数对象。
分为:算法类函数对象,关系运算类函数对象,逻辑运算类函数对象。这些函数对象所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象(匿名对象)来履行函数功能。
使用内建函数对象,需要引入头文件#include<functional>
3.1 算法类函数对象
6个算法类函数对象,除了negate是一元运算,其它的都是二元运算。
1 2 3 4 5 6 template <class T > T plus<T>;template <class T > T minus<T>;template <class T > T multiplies<T>;template <class T > T divides<T>;template <class T > T modulus<T>;template <class T > T nagete<T>;
案例:
1 2 3 4 5 void test07 () { plus<int > p; cout<<p (12 ,15 )<<endl; cout<<plus<int >()(123 ,23 )<<endl; }
运行结果:
3.2 关系运算类函数对象
6个关系运算类函数对象,每一种都是二元运算,也是二元谓词(返回值为bool
类型)。
1 2 3 4 5 6 template <class T > bool equal_to<T>;template <class T > bool not_equal_to<T>;template <class T > bool greater<T>;template <class T > bool greater_equal<T>;template <class T > bool less<T>;template <class T > bool less_equal<T>;
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void test08 () { vector<int > v; v.push_back (10 ); v.push_back (30 ); v.push_back (15 ); v.push_back (40 ); for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; sort (v.begin (),v.end ()); cout<<"默认从小到大:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; sort (v.begin (),v.end (),greater<int >()); cout<<"内建函数对象作为二元谓词 从大到小:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; }
运行结果:
3.3 逻辑运算类函数对象
not为一元谓词,其余为二元谓词。
1 2 3 template <class T > bool logical_and<T>;template <class T > bool logical_or<T>;template <class T > bool logical_not<T>;
四、函数对象适配器
拓展函数的参数接口(假如函数有一个参数,在拓展一个接口,就可以传递两个参数)
如果我们想使用绑定适配器,需要我们自己的函数对象继承binary_function或者unary_function,根据我们函数对象是一元函数对象还是二元函数对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class myPrintVectorInt :public binary_function<int ,int ,void >{public : void operator () (int val) { cout<<val<<" " ; } void operator () (int val,int temp) const { cout<<val+temp<<" " ; } }; void test09 () { vector<int > v; v.push_back (10 ); v.push_back (30 ); v.push_back (15 ); v.push_back (40 ); for_each(v.begin (),v.end (),bind2nd (myPrintVectorInt (),100 )); cout<<endl; for_each(v.begin (),v.end (),myPrintVectorInt ()); cout<<endl; }
运行结果:
总结:
第一步:使用bind2nd或者bind1st绑定参数 要对类进行绑定即仿函数(函数对象)
第二步:公有继承binary_function或unary_function
第三步:参数的萃取 <int,int,void> 分别是第一个形参第二个形参和返回值
第四步:对operator()进行const修饰
bind2nd与bind1st的区别:绑定的参数位置不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class myPrintVectorInt :public binary_function<int ,int ,void >{public : void operator () (int val) { cout<<val<<" " ; } void operator () (int val,int temp) const { cout<<"val:" <<val<<" " <<"temp:" <<temp<<"," <<endl; } }; void test10 () { vector<int > v; v.push_back (10 ); v.push_back (30 ); v.push_back (15 ); v.push_back (40 ); for_each(v.begin (),v.end (),bind2nd (myPrintVectorInt (),100 )); cout<<endl; for_each(v.begin (),v.end (),bind1st (myPrintVectorInt (),100 )); cout<<endl; }
运行结果:
总结:
bind2nd:将外界数据绑定到第二个参数
bind1st:将外界数据绑定到第一个参数
五、一元取反适配器
not1()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class myGreaterThan30 :public unary_function<int ,bool >{public : bool operator () (int val) const { return val>30 ; } }; void test11 () { vector<int > v; v.push_back (10 ); v.push_back (20 ); v.push_back (30 ); v.push_back (40 ); v.push_back (50 ); vector<int >::iterator ret; ret = find_if (v.begin (),v.end (),myGreaterThan30 ()); cout<<"*ret=" <<*ret<<endl; ret = find_if (v.begin (),v.end (),not1 (myGreaterThan30 ())); cout<<"*ret=" <<*ret<<endl; }
运行结果:
六、二元取反适配器
not2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class myGreaterInt :public binary_function<int ,int ,bool >{public : bool operator () (int v1,int v2) const { return v1>v2; } }; void test12 () { vector<int > v; v.push_back (4 ); v.push_back (9 ); v.push_back (1 ); v.push_back (12 ); v.push_back (32 ); cout<<"原始顺序:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; sort (v.begin (),v.end ()); cout<<"默认从小到大:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; sort (v.begin (),v.end (),myGreaterInt ()); cout<<"指定排序规则从大到小:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; sort (v.begin (),v.end (),not2 (myGreaterInt ())); cout<<"not2将指定排序规则从大到小改成从小到大:" ; for_each(v.begin (),v.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; }
运行结果:
七、成员函数适配器
利用mem_fun_ref 将Person内部成员函数适配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Person {public : string name; int age; public : Person (string name,int age){ this ->name = name; this ->age = age; } void myPrint () { cout<<"name=" <<this ->name<<" " <<"age=" <<this ->age<<endl; } }; void test13 () { vector<Person> v; v.push_back (Person ("小花" ,18 )); v.push_back (Person ("小明" ,17 )); v.push_back (Person ("lucy" ,23 )); v.push_back (Person ("bob" ,22 )); for_each(v.begin (),v.end (),myPrintPerson); cout<<"**************" <<endl; for_each(v.begin (),v.end (),mem_fun_ref (&Person::myPrint)); }
运行结果:
八、普通函数作为适配器(函数指针作为适配器)
ptr_fun()
1 2 3 4 5 6 7 8 9 10 void test14 () { vector<int > v; v.push_back (10 ); v.push_back (20 ); v.push_back (30 ); v.push_back (40 ); for_each(v.begin (),v.end (),bind2nd (ptr_fun (myPrintInt),100 )); cout<<endl; }
总结:与函数对象适配器类似,只是普通函数不是一个类,需要加个ptr_fun()
。
九、算法概述
算法只要是由头文件组成,是所有STL头文件中最大的一个,其中常用的功能涉及到比较、交换、查找、遍历、复制、修改、反转、排序、合并等,体积很小,只包括在几个序列容器上进行的简单运算的模板函数,定义了一些模板类,用以声明函数对象。
9.1 常用遍历算法
9.1.1 for_each 遍历算法
1 2 3 4 5 6 7 8 for_each(iterator beg,iterator end,_callback);
将指定容器区间元素搬运到另一容器中
注意: transform 不会给目标容器分配内存,所以需要我们提前分配好内存
系统虽然可能会调用push_back
,但是我们最好还是预先分配一下内存resize()
;
1 2 3 4 5 6 7 8 transform (iterator beg1,iterator end1,iterator beg2,_callback);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void test15 () { vector<int > v1; v1.push_back (10 ); v1.push_back (20 ); v1.push_back (30 ); v1.push_back (40 ); vector<int > v2; v2.resize (v1.size ()); transform (v1.begin (),v1.end (),v2.begin (),myTransInt); transform (v1.begin (),v1.end (),v2.begin (),myTransInt1 ()); cout<<"v2:" ; for_each(v2.begin (),v2.end (),[](int val){ cout<<val<<" " ; }); cout<<endl; }
运行结果:
9.2 常用查找算法
9.2.1 find() 查找元素
1 2 3 4 5 6 7 8 find (iterator beg,iterator end,value);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void test16 () { vector<int > v1; v1.push_back (10 ); v1.push_back (20 ); v1.push_back (30 ); v1.push_back (40 ); vector<int >::iterator ret; ret = find (v1.begin (),v1.end (),30 ); if (ret != v1.end ()){ cout<<"查找到元素:" <<*ret<<endl; }else { cout<<"没有查到" <<endl; } }
运行结果:
案例:
如果是自定义数据,需要重载==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Person {public : string name; int age; public : Person (string name,int age){ this ->name = name; this ->age = age; } bool operator ==(const Person &ob){ return (this ->age == ob.age && this ->name == ob.name); } }; void test17 () { vector<Person> v1; v1.push_back (Person ("lucy" ,18 )); v1.push_back (Person ("bob" ,21 )); v1.push_back (Person ("mick" ,19 )); v1.push_back (Person ("lily" ,23 )); vector<Person>::iterator ret; ret = find (v1.begin (),v1.end (),Person ("mick" ,19 )); if (ret != v1.end ()){ cout<<"查找到元素:" <<(*ret).name<<" " <<(*ret).age<<endl; }else { cout<<"没有查到" <<endl; } }
运行结果:
9.2.2 find_if条件查找
1 2 3 4 5 6 7 find_if (iterator beg,iterator end,_callback);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class myGreaterThan25A {public : bool operator () (int &val) { return val > 25 ; } }; void test18 () { vector<int > v1; v1.push_back (10 ); v1.push_back (20 ); v1.push_back (30 ); v1.push_back (40 ); vector<int >::iterator ret; ret = find_if (v1.begin (),v1.end (),myGreaterThan25); ret = find_if (v1.begin (),v1.end (),myGreaterThan25A ()); if (ret != v1.end ()){ cout<<"查找到大于25元素:" <<*ret<<endl; }else { cout<<"没有查到" <<endl; } }
运行结果:
9.2.3 adjacent_find 算法 查找相邻重复元素
1 2 3 4 5 6 7 8 adjacent_find (iterator beg,iterator end,_callback);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 bool fun1 (int v1,int v2) { return v1==v2; } void test19 () { vector<int > v1; v1.push_back (10 ); v1.push_back (20 ); v1.push_back (20 ); v1.push_back (40 ); v1.push_back (50 ); v1.push_back (50 ); v1.push_back (70 ); for_each(v1.begin (),v1.end (),[](int &val){ cout<<val<<" " ; }); cout<<endl; vector<int >::iterator ret; ret = adjacent_find (v1.begin (),v1.end ()); ret = adjacent_find (v1.begin (),v1.end (),fun1); if (ret != v1.end ()){ cout<<"找到第一个相邻重复元素:" <<*ret<<endl; }else { cout<<"没有相邻重复元素" <<endl; } }
运行结果:
对于普通数据时不需要回调函数的,也可以写,对于自定义数据需要回调函数,也可以重载== 内存比较???!不是内存比较,如果不传第三个参数默认调用函数对象模板中的equal_to<>()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 template <class _FwdIt , class _Pr >_NODISCARD _FwdIt adjacent_find (const _FwdIt _First, _FwdIt _Last, _Pr _Pred) { _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); auto _ULast = _Get_unwrapped(_Last); if (_UFirst != _ULast) { for (auto _UNext = _UFirst; ++_UNext != _ULast; _UFirst = _UNext) { if (_Pred(*_UFirst, *_UNext)) { _ULast = _UFirst; break ; } } } _Seek_wrapped(_Last, _ULast); return _Last; } template <class _FwdIt >_NODISCARD _FwdIt adjacent_find (const _FwdIt _First, const _FwdIt _Last) { return _STD adjacent_find (_First, _Last, equal_to<>()); }
案例:自定义数据使用回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Person {public : string name; int age; public : Person (string name, int age) { this ->name = name; this ->age = age; } }; void test20 () { vector<Person> v1; v1.push_back (Person ("lucy" , 18 )); v1.push_back (Person ("bob" , 21 )); v1.push_back (Person ("bob" , 21 )); v1.push_back (Person ("mick" , 19 )); v1.push_back (Person ("lily" , 23 )); for_each(v1.begin (), v1.end (), [](Person& ob) { cout << (ob).name << " " << (ob).age << endl; }); cout << endl; vector<Person>::iterator ret; ret = adjacent_find (v1.begin (), v1.end (), fun2); if (ret != v1.end ()) { cout << "找到第一个相邻重复元素:" << (*ret).name << " " << (*ret).age << endl; } else { cout << "没有相邻重复元素" << endl; } }
运行结果:
案例:自定义数据使用二元谓词
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Person {public : string name; int age; public : Person (string name, int age) { this ->name = name; this ->age = age; } }; void test21 () { vector<Person> v1; v1.push_back (Person ("lucy" , 18 )); v1.push_back (Person ("bob" , 21 )); v1.push_back (Person ("bob" , 21 )); v1.push_back (Person ("mick" , 19 )); v1.push_back (Person ("lily" , 23 )); for_each(v1.begin (), v1.end (), [](Person& ob) { cout << (ob).name << " " << (ob).age << endl; }); cout << endl; vector<Person>::iterator ret; ret = adjacent_find (v1.begin (), v1.end (), fun2a ()); if (ret != v1.end ()) { cout << "找到第一个相邻重复元素:" << (*ret).name << " " << (*ret).age << endl; } else { cout << "没有相邻重复元素" << endl; } }
运行结果:
案例:自定义数据重载==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Person {public : string name; int age; public : Person (string name, int age) { this ->name = name; this ->age = age; } bool operator ==(const Person &ob){ return (this ->age == ob.age && this ->name == ob.name); } }; void test22 () { vector<Person> v1; v1.push_back (Person ("lucy" , 18 )); v1.push_back (Person ("bob" , 21 )); v1.push_back (Person ("bob" , 21 )); v1.push_back (Person ("mick" , 19 )); v1.push_back (Person ("lily" , 23 )); for_each(v1.begin (), v1.end (), [](Person& ob) { cout << (ob).name << " " << (ob).age << endl; }); cout << endl; vector<Person>::iterator ret; ret = adjacent_find (v1.begin (), v1.end ()); if (ret != v1.end ()) { cout << "找到第一个相邻重复元素:" << (*ret).name << " " << (*ret).age << endl; } else { cout << "没有相邻重复元素" << endl; } }
9.2.4 binary_search 算法 二分查找法(前提:容器必须有序)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 binary_search (iterator beg,iterator end,value);template <class _FwdIt , class _Ty >_NODISCARD bool binary_search (_FwdIt _First, _FwdIt _Last, const _Ty& _Val) { return _STD binary_search (_First, _Last, _Val, less<>()); }
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void test23 () { vector<int > v1; srand (time (NULL )); for (int i=0 ;i<50 ;i++){ int randomNum = rand ()%100 ; v1.push_back (randomNum); } sort (v1.begin (), v1.end ()); int n=1 ; for_each(v1.begin (), v1.end (), [&](int & val) { cout << val << "\t" ; if (n%10 == 0 ) cout<<"\n" ; n++; }); cout << endl; bool b=binary_search (v1.begin (),v1.end (),58 ); if (b==true ){ cout<<"查询成功" <<endl; }else { cout<<"数据未查到" <<endl; } }
运行结果:
9.2.5 count 算法 统计元素出现次数
1 2 3 4 5 6 7 8 count (iterator beg,iterator end,value);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void test24 () { vector<int > v; v.push_back (10 ); v.push_back (11 ); v.push_back (12 ); v.push_back (12 ); v.push_back (13 ); v.push_back (13 ); v.push_back (13 ); v.push_back (14 ); int ct=0 ; ct = count (v.begin (),v.end (),13 ); cout<<"13出现的次数:" <<ct<<endl; }
运行结果:
9.2.6 count_if 算法 条件统计元素出现次数
1 2 3 4 5 6 7 8 count_if (iterator beg,iterator end,_callback);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 bool myGreaterThan12 (int &val) { return val > 12 ; } class myGreaterThan13 {public : bool operator () (int &val) { return val > 13 ; } }; void test25 () { vector<int > v; v.push_back (10 ); v.push_back (11 ); v.push_back (12 ); v.push_back (12 ); v.push_back (13 ); v.push_back (13 ); v.push_back (13 ); v.push_back (14 ); v.push_back (8 ); v.push_back (19 ); v.push_back (68 ); int ct=0 ; ct = count_if (v.begin (),v.end (),myGreaterThan12); cout<<"大于12元素出现的次数:" <<ct<<endl; cout<<"************" <<endl; ct = count_if (v.begin (),v.end (),myGreaterThan13 ()); cout<<"大于13元素出现的次数:" <<ct<<endl; cout<<"************" <<endl; ct = count_if (v.begin (),v.end (),bind2nd (greater<int >(),14 )); cout<<"大于14元素出现的次数:" <<ct<<endl; }
运行结果:
9.3 常用排序算法
9.3.1 merge 算法
1 2 3 4 5 6 7 8 9 10 11 merge (iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
v1和v2无序 合并出的v3如图:
案例:
要预先设置目标容器的大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 void test26 () { vector<int > v1; srand (time (NULL )); cout<<"v1:" ; for (int i=0 ;i<6 ;i++){ int randomNum = rand ()%100 ; v1.push_back (randomNum); } for_each(v1.begin (), v1.end (), [&](int & val) { cout << val << " " ; }); cout << endl; sort (v1.begin (),v1.end ()); vector<int > v2; cout<<"v2:" ; for (int i=0 ;i<6 ;i++){ int randomNum = rand ()%100 ; v2.push_back (randomNum); } for_each(v2.begin (), v2.end (), [&](int & val) { cout << val << " " ; }); cout << endl; sort (v2.begin (),v2.end ()); vector<int > v3; v3.resize (v1.size ()+v2.size ()); merge (v1.begin (),v1.end (),v2.begin (),v2.end (),v3.begin ()); cout<<"v3:" ; for_each(v3.begin (), v3.end (), [&](int & val) { cout << val << " " ; }); cout << endl; }
运行结果:
既然无序的合并也是无序的,要保证两个容器全部有序合并出来才是有序的,其实我觉得可以无序合并的结果最后做一个排序,即把无序的v3进行排序就行了阿。
注意:预先设置容器大小时,不能使用reserve要用resize,使用reserve,只会实现分配容量,大小还是0,相当于没有迭代器,这时候进行合并时,函数操作的是一个个的迭代器,这时候会出现问题,而既没有使用reserve和resize会出现段错误。
9.3.2 sort 算法 排序算法
1 2 3 4 5 6 7 sort (iterator beg,iterator end,_callback);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void test27 () { vector<int > v; for (int i=0 ;i<6 ;i++){ int randomNum = rand ()%100 ; v.push_back (randomNum); } cout<<"排序前:" ; for_each(v.begin (), v.end (), [&](int & val) { cout << val << " " ; }); cout << endl; sort (v.begin (),v.end ()); cout<<"排序后:" ; for_each(v.begin (), v.end (), [&](int & val) { cout << val << " " ; }); cout << endl; sort (v.begin (),v.end (),greater<int >()); cout<<"排序后:" ; for_each(v.begin (), v.end (), [&](int & val) { cout << val << " " ; }); cout << endl; }
运行结果:
9.3.3 random_shuffle算法
1 2 3 4 5 6 random_shuffle (iterator beg,iterator end);
案例:
需要设置种子
1 2 3 4 5 6 7 8 9 10 11 12 void test28 () { vector<int > v; for (int i=0 ;i<10 ;i++){ v.push_back (i); } srand (time (NULL )); random_shuffle (v.begin ()+5 ,v.end ()); for_each(v.begin (),v.end (),[](int &val){ cout<<val<<" " ; }); cout<<"\n" ; }
运行结果:
9.3.4 reverse算法
1 2 3 4 5 6 reverse (iterator beg,iterator end);
案例:
1 2 3 4 5 6 7 8 9 10 11 12 void test29 () { vector<int > v; for (int i=0 ;i<10 ;i++){ v.push_back (i); } srand (time (NULL )); reverse (v.begin ()+5 ,v.end ()); for_each(v.begin (),v.end (),[](int &val){ cout<<val<<" " ; }); cout<<"\n" ; }
运行结果:
9.4 常用拷贝和替换算法
9.4.1 copy算法
1 2 3 4 5 6 7 copy (iterator beg,iterator end,iterator dest);
要事先设置空间
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void test30 () { vector<int > v1; for (int i=0 ;i<10 ;i++){ v1.push_back (i); } cout<<"v1:" ; for_each(v1.begin (),v1.end (),[](int &val){ cout<<val<<" " ; }); cout<<"\n" ; vector<int > v2; v2.resize (v1.size ()); copy (v1.begin (),v1.end (),v2.begin ()); cout<<"v2:" ; for_each(v2.begin (),v2.end (),[](int &val){ cout<<val<<" " ; }); cout<<"\n" ; }
运行结果:
copy高级用法:
用copy输出
1 2 3 4 5 6 7 8 void test31 () { vector<int > v1; for (int i=0 ;i<10 ;i++){ v1.push_back (i); } copy (v1.begin (),v1.end (),ostream_iterator<int >(cout,"~~" )); cout<<endl; }
运行结果:
9.4.2 replace算法 将容器内指定范围的旧元素修改为新元素
1 2 3 4 5 6 7 8 replace (iterator beg,iterator end,oldvalue,newvalue);
9.4.3 replace_if算法 将容器内指定范围满足条件的元素替换为新元素
1 2 3 4 5 6 7 8 replace_if (iterator beg,iterator end,_callback,newvalue);
9.4.4 swap算法
swap(container c1,container c2);
1 2 3 4 template <class _Ty , class _Alloc >void swap (vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right) noexcept { _Left.swap (_Right); }
1 2 3 4 5 6 7 public : void swap (vector& _Right) noexcept { if (this != _STD addressof (_Right)) { _Pocs(_Getal(), _Right._Getal()); _Mypair._Myval2._Swap_val(_Right._Mypair._Myval2); } }
1 2 3 4 5 6 7 8 9 10 template <class _Alloc >void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_swap::value) { _Swap_adl(_Left, _Right); } else { _STL_ASSERT(_Left == _Right, "containers incompatible for swap" ); (void ) _Left; (void ) _Right; } }
层层套 我tm快烦死了,应该就是交换了两个容器的指向
9.5 常用算数生成算法
9.5.1 accumulate算法 计算容器元素累积总和
1 2 3 4 5 6 7 8 accumulate (iterator beg,iterator end,value);
案例:
运行结果:
9.5.2 fill算法 向容器中添加元素
1 2 3 4 5 6 7 fill (iterator beg,iterator end,value);
案例:
运行结果:
9.6 集合算法
9.6.1 set_intersection算法 求两个set集合的交集
1 2 3 4 5 6 7 8 9 10 11 set_intersection (iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
案例:
运行结果:
9.6.2 set_union 求两个set集合的并集
1 2 3 4 5 6 7 8 9 10 11 set_union (iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
案例:
运行结果:
9.6.3 set_difference 求两个set集合的差集
1 2 3 4 5 6 7 8 9 10 11 set_difference (iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
案例:
运行结果:
十、STL综合案例
演讲比赛
比赛规则:
某市举行一场演讲比赛( speech_ contest ),共有24个人参加。比赛共三轮,前两轮为淘汰赛,笫三轮为决赛。
比赛方式:分组比赛,每组6个人;选于每次要随机分组,进行比赛;
第-轮分为4个小组,每组6个人。比如编号为: 100-123.整体进行抽签
(draw)后顺序演讲。当小组演讲完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
第二轮分为2个小组,每组6人。比赛完毕,淘汰组内排名最后的三个选于,然后继续下一-个小组的比赛。
第三轮只剩下1组6个人,本轮为决赛,选出前三名。比赛评分: 10 个评委打分,去除最低、最高分,求平均分每个选手演讲完由10个评委分别打分。该选手的最终得分是去掉一一个最高分和-一个最低分,求得剩下的8个成绩的平均分。选手的名次按得分降序排列。
用STL编程,求解这个问题1) 请打印出所有选于的名字与参赛号,并以参赛号的升序排列。2)打印每–轮比赛后,小组比赛成绩和小组晋级名单
需求分析: 1) 产生选手( ABCDEFGHIJKLMNOPQRSTUVWX )姓名、得分;选手编号
第1轮选手抽签选手比赛查看比赛结果
第2轮选手抽签选手比赛查看比赛结果
第3轮选手抽签选手比赛查看比赛结果
实现思路:需要把选于信息、选于得分信息、选于比赛抽签信息、选手的晋级信息保存在容器中,需要涉及到各个容器的选型。选 手可以设计一个类Speaker(姓名和得分)所有 选手的编号可以单独放在一个vector容器中,做抽签用所有选手编号和选手信息,可以放在容器内:map<int,