知识点
1.概述
算法中包含很多对容器进行处理的算法,使用迭代器来标识要处理的数据或数据段、以及结果的存放位置,有的函数还作为对象参数传递给另一个函数,实现数据的处理。
这些算法可以操作在多种容器类型上,所以称为“泛型”,泛型算法不是针对容器编写,而只是单独依赖迭代器和迭代器操作实现。
2.分类
1、非修改式序列操作:不改变容器的内容,如find()、for_each()等。
2、修改式序列操作:可以修改容器中的内容,如transform()、random_shuffle()、copy等。
3、排序和相关操作:包括各种排序函数等,如sort()等。
4、通用数字运算:计算两个容器的内部乘积等。3.一元函数以及一元断言/一元谓词
一元函数:函数的参数只有一个;
一元断言/一元谓词:函数的参数只有一个,并且返回类型是bool类型。
二元函数:函数的参数有两个;
二元断言/二元谓词:函数的参数两个,并且返回类型是bool类型。4.函数适配器——函数绑定器,bind1st,bind2nd,bind.
模板形式中,两个函数绑定器的第一个参数就是一个函数,第二个参数就是一个数字,如果F是一个二元函数(普通二元函数或者二元谓词),我们可以绑定F的第一个参数(bind1st)或者第二个参数(bind2nd),达到我们想要的效果(使用二元谓词的效果)
bind函数的使用相比于bind1st以及bind2nd更加的具有通用性,因为后者只能绑定一个参数,而bind可以绑定任意个参数。bind可以绑定到普通函数、成员函数。
bind函数的返回类型到底是什么呢?其实就是一种函数类型,就是一种可以装函数类型的容器,即:function。有了function之后,bind函数还可以绑定到数据成员上面来5.std::function与std::bind结合使用体现出多态性的例子,也就是注册回调函数与执行回调函数。
6.成员函数绑定器.
em_fun() //容器参数为类指针
mem_fun_ref() //容器参数为类对象
mem_fn()// 两者都能用(C++11),其使用更具有广泛性,直接使用代码就ok
1.非修改式算法,for_each,find的用法
1.使用for_each和匿名函数实现打印vector
2.algorithm中count和find的使用方法,find返回的是一个迭代器
接口:
template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
//UnaryFunction一元函数
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
using std::cout;
using std::endl;
using std::for_each;
using std::vector;
using std::ostream_iterator;
void myPrint(int &num)
{
++num;
cout<<num<<" ";
}
void test01()
{
vector<int> numberVec={1,3,5,7,9,2,3,4,5};
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//for_each进行遍历打印
for_each(numberVec.begin(),numberVec.end(),myPrint);
cout<<endl;
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//匿名函数lambda实现打印
for_each(numberVec.begin(),numberVec.end(),[](int num){cout<<num<<" ";});
cout<<endl;
}
void test02()
{
//count的使用
vector<int> numberVec={1,3,5,7,9,2,3,4,5,3,3,3};
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
int ret = count(numberVec.begin(),numberVec.end(),3);
cout<<"count="<<ret<<endl;
//find返回的是一个迭代器
auto it= find(numberVec.begin(),numberVec.end(),13);
cout<<"find(9)="<<*it<<endl;
}
int main()
{
test01();
cout<<endl<<endl;
test02();
return 0;
}
/*
1 3 5 7 9 2 3 4 5
2 4 6 8 10 3 4 5 6
2 4 6 8 10 3 4 5 6
2 4 6 8 10 3 4 5 6
1 3 5 7 9 2 3 4 5 3 3 3
count=5
find(9)=0
*/
2.修改式算法(copy/remove_if)
template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p);
//UnaryPredicate:一元谓词,函数参数只有一个,并且返回的是bool类型
//1.remove_if返回要删除的数据的首个迭代器,把要保留的数据往前移了
//2.remove_if必须配合erase使用,才能把数据干掉,再配合shrink_to_fit()回收相应内存空间
删除vector中大于4的元素
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
using std::cout;
using std::endl;
using std::for_each;
using std::vector;
using std::ostream_iterator;
void myPrint(int &num)
{
++num;
cout<<num<<" ";
}
bool func(int number)
{
return number>4;
}
void test01()
{
vector<int> numberVec={1,3,5,7,9,2,3,4,4,6,9,8,7,7};
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
auto it = remove_if(numberVec.begin(),numberVec.end(),func);
//把小于等于4的数据往前移,返回要删除的数据的首个迭代器
cout<<numberVec.capacity()<<endl;
//remove_if必须配合erase使用,才能把数据干掉
numberVec.erase(it,numberVec.end());//返回要删除的第一个数据迭代器
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
numberVec.shrink_to_fit();
cout<<numberVec.capacity()<<endl;
}
//remove_if写成匿名函数形式
void test02()
{
vector<int> numberVec={1,3,5,7,9,2,3,4,4,6,9,8,7,7};
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
auto it = remove_if(numberVec.begin(),numberVec.end(),
[](int num)
-> bool {//返回类型的书写方式,可以省略不写
return num>4;
});
//把小于等于4的数据往前移,返回要删除的数据的首个迭代器
cout<<numberVec.capacity()<<endl;
//remove_if必须配合erase使用,才能把数据干掉
numberVec.erase(it,numberVec.end());//返回要删除的第一个数据迭代器
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
numberVec.shrink_to_fit();
cout<<numberVec.capacity()<<endl;
}
int main()
{
test01();
test02();
return 0;
}
3.bind1st和bind2nd
template< class F, class T >
std::binder1st<F> bind1st( const F& f, const T& x );
//把x绑定到二言谓词的第一个或者第二个参数
template< class F, class T >
std::binder2nd<F> bind2nd( const F& f, const T& x );
/* 删除vector中大于4的元素*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
using std::cout;
using std::endl;
using std::for_each;
using std::vector;
using std::ostream_iterator;
using std::copy;
void test01()
{
vector<int> numberVec = {1,3,5,7,9,8,67,32,2,3,4,7};
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;//1 3 5 7 9 8 67 32 2 3 4 7
//把4绑定到std::less<int>()函数对象的第一个参数
auto it = remove_if(numberVec.begin(),numberVec.end(),std::bind1st(std::less<int>(),4));
numberVec.erase(it,numberVec.end());
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
}
void test02()
{
vector<int> numberVec = {1,3,5,7,9,8,67,32,2,3,4,7};
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;//1 3 5 7 9 8 67 32 2 3 4 7
//把4绑定到std::greater<int>()函数对象的第2个参数
auto it = remove_if(numberVec.begin(),numberVec.end(),std::bind2nd(std::greater<int>(),4));
numberVec.erase(it,numberVec.end());
copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
numberVec.shrink_to_fit();
}
int main()
{
test01();
test02();
return 0;
}
/*
1 3 5 7 9 8 67 32 2 3 4 7
1 3 2 3 4
1 3 5 7 9 8 67 32 2 3 4 7
1 3 2 3 4
*/
5.bind的使用
test01():.bind绑定到普通函数
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <functional>
using std::cout;
using std::endl;
using std::for_each;
using std::vector;
using std::ostream_iterator;
using std::copy;
using std::bind;
int add(int x, int y)
{
return x+y;
}
int multiply(int x,int y,int z)
{
cout<<"int multiply(int,int,int)"<<endl;
return x*y*z;
}
//1.绑定到普通函数
void test01()
{
//1.bind绑定两个参数
auto f = bind(add, 1,2);//把参数1,2绑定到add,不用给f传参
//f的类型:int(),直接调用
cout<<f()<<endl;//3
//2.bind 绑定三个参数,f1类型:int()
auto f1 = bind(multiply, 1,2,3);
cout<<f1()<<endl;//6
}
2.bind绑定到类的成员函数
class Example
{
public:
int add(int x,int y)
{
cout<<"int Example::add(int,int)"<<endl;
return x+y;
}
int data = 100;//c++11提出了的初始化的方式
};
//2.bind绑定到类的成员函数
void test02()
{
Example ex;
auto f1 = bind(&Example::add, &ex,1,2);
//加&ex的原因:成员函数内蕴含了一个指针this
cout<<f1()<<endl;//3
}
3.placeholder占位符的使用
//3.placeholder占位符的使用
void test03()
{
int number = 100;
auto f=bind(add,std::placeholders::_1,
std::placeholders::_3);
//绑定了两个参数,未知参数
cout<<f(20,10,30)<<endl;
}
/*
50
*/
//4.placeholders的作用
void func4(int x1,int x2,int x3,const int &x4, int x5)
{
cout<<"("<<x1
<<","<<x2
<<","<<x3
<<","<<x4
<<","<<x5<<")"<<endl;
}
void test04()
{
int number = 100;
auto f = std::bind(func4,std::placeholders::_11,std::placeholders::_5
,number,std::cref(number),number);//placeholders占位符:表示形参的位置
//f(111,22,2);placeholders后面的数字代表传的是实参处于实参列表的位置
number = 500;//参数传递使用的是值传递,用cref来改变,const ref
//cref:引用的包装器
f(1,3,5,7,9,12,3,212,2123,444,122);//第11个数:122,第5个数:9
//除了第5个和第11个数,其余的数没多大用处,只用来占位
}
/*
(122,9,100,500,100)
*/
4.用函数类型(function)容器来接受bind函数返回的类型
int add(int x, int y)
{
return x+y;
}
int multiply(int x,int y,int z)
{
cout<<"int multiply(int,int,int)"<<endl;
return x*y*z;
}
class Example
{
public:
int add(int x,int y)
{
cout<<"int Example::add(int,int)"<<endl;
return x+y;
}
int data = 100;//c++11提出了的初始化的方式
};
void test05()
{
//int (int,int)====> int(),返回的是一个int类型的参数?
std::function<int()> f = bind(add, 1,2);
cout<<"f()="<<f()<<endl;//3
auto f2 = bind(multiply,3,4,5);
cout<<"f2()="<<f2()<<endl;//60
cout<<endl;
Example ex;
std::function<int()> f3 = bind(&Example::add,&ex,4,5);//成员函数中隐藏了一个this指针
cout<<f3()<<endl;//9
//绑定到成员,对象里来
f3 = bind(&Example::data,&ex);
cout<<"data:f3()="<<f3()<<endl;//100
//int (int ,int)====> int add(1,xxxx);绑定一个参数,另外一个在调用时输入
std::function<int(int)> f4 = bind(add, 1, std::placeholders::_1);
cout<<f4(3)<<endl;//4
std::function<int(int,int,int)> f5 = bind(add, std::placeholders::_3, std::placeholders::_1);
cout<<f5(3,12,300)<<endl;//303
}
6.bind+function的特点的使用来实现类的多态--也就是注册回调函数与执行回调函数。
1.回调函数:把函数的注册和函数的执行分开。
2.bind:返回的是一种函数类型,是一种可以装函数类型的容器。
template< class R, class F, class... Args >
bind( F&& f, Args&&... args )
3.有了function之后,bind函数还可以绑定到数据成员上面来,其实就是int()这中类型上来。
#include <math.h>
#include <iostream>
#include <functional>
#include <string>
using std::string;
using std::cout;
using std::endl;
using std::bind;
using std::function;
class Figure
{
public:
//1.定义函数的类型
using DisplayCallback = std::function<void()>; //用DisplayCallback代替std::function<void()>,
//用DisplayCallback声明的对象,是一个可以接受void()---void无参类型的函数的容器
using AreaCallback = std::function<double()>; //用AreaCallback声明的对象,是一个接受doulbe()类型的容器
using AreaCallback_double = std::function<double(double)>;//声明一个接收double(double)类型的容器,传入参数pi
DisplayCallback _display;
AreaCallback _showarea;
AreaCallback_double _area_double;
//2.注册回调函数
void SetDisplayCallback(DisplayCallback &&dc)//dc用来接受bind返回的对象,是一个右值
{
_display =std::move(dc);//用移动语义转移资源
}
void SetAreaCallback(AreaCallback &&ac)//dc用来接受bind返回的对象,是一个右值
{
_showarea =std::move(ac);//用移动语义转移资源
}
void SetAreaCallback_double(AreaCallback_double &&acd)
{
_area_double = std::move(acd);
}
//3.执行回调函数
void Execute_Display()const
{
if(_display)
{
_display();
}
}
double Execute_Area()const
{
if(_showarea)
{
return _showarea();
}
else
{
return 0;
}
}
double Execute_Area_double(const double &pi)const
{
if(_area_double)
{
return _area_double(pi);
}
else
{
return 0;
}
}
};
class Rectangle
{
public:
Rectangle(double len = 0, double width = 0)
: _length(len)
, _width(width)
{}
void display() const
{
cout << "Rectangle(length)= "<<_length
<<endl<<"Rectangle(width)="<<_width<<endl;
}
double area() const
{
return _length * _width;
}
private:
double _length;
double _width;
};
class Circle
{
public:
Circle(double len = 0)
: _didus(len)
{}
void print() const
{
cout << "Circle(Radius)= "<<_didus<<endl ;
}
double printArea(const double &pi) const//传个pi进来
{
return pi * _didus * _didus;
}
private:
double _didus;
};
class Traingle
{
public:
Traingle(double a = 0, double b = 0, double c = 0)
: _a(a)
, _b(b)
, _c(c)
{
}
void show() const
{
cout << "Traingle(a)="<<_a<<endl ;
cout << "Traingle(a)="<<_b<<endl ;
cout << "Traingle(a)="<<_c<<endl ;
}
double showArea() const
{
double p = (_a + _b + _c)/2;
return sqrt(p * (p - _a) * (p - _b) * (p - _c));
}
private:
double _a;
double _b;
double _c;
};
void test01()
{
Rectangle rectagle(10, 20);
Circle circle(100);
Traingle traingle(3, 4, 5);
Figure figure;
//1.注册回调函数,Rectangle回调函数
//2.执行回调函数Rectangle回调函数
figure.SetDisplayCallback(bind(&Rectangle::display, &rectagle));
figure.Execute_Display();
figure.SetAreaCallback(bind(&Rectangle::area,&rectagle));
cout<<"S(Rectangle)="<<figure.Execute_Area()<<endl;//Area返回是一个double类型的值
//1.注册回调函数,Circle回调函数
//2.执行回调函数Circle回调函数
figure.SetDisplayCallback(bind(&Circle::print, &circle));
figure.Execute_Display();//打印半径
//传入实参,能顺利执行
figure.SetAreaCallback_double(bind(&Circle::printArea, &circle, std::placeholders::_1));
cout<<"S(Circle)="<<figure.Execute_Area_double(3.14)<<endl;//31400
//1.注册回调函数,Traingle回调函数
//2.执行回调函数Triangle回调函数
figure.SetDisplayCallback(bind(&Traingle::show, &traingle));
figure.Execute_Display();
figure.SetAreaCallback(bind(&Traingle::showArea,&traingle));
cout<<"S(Triangle)="<<figure.Execute_Area()<<endl;
}
int main()
{
test01();
return 0;
}
/*
Rectangle(length)= 10
Rectangle(width)=20
S(Rectangle)=200
Circle(Radius)= 100
S(Circle)=31400
Traingle(a)=3
Traingle(a)=4
Traingle(a)=5
S(Triangle)=6
*/
7.成员函数绑定器.
em_fun() //容器参数为类指针
mem_fun_ref() //容器参数为类对象
mem_fn() //两者都能用(C++11),其使用更具有广泛性,直接使用代码就ok
/* 用mem_fn绑定类中的成员函数来实现remove_if筛选和进行for_each打印*/
#include <iostream>
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using std::cout;
using std::endl;
using std::vector;
using std::mem_fn;
class Number
{
public:
Number(size_t data=0)
:_data(data)
{
}
void print()const
{
cout<<_data<<" ";
}
bool isEven()const//偶数
{
return 0==_data%2;
}
bool isPrime()const//判断一个数是否为质数
{
if(1==_data)
{
return false;
}
for(size_t idx = 2; idx<=_data/2;++idx)
{
if(0==_data%idx)
{
return true;
}
}
return false;
}
private:
size_t _data;
};
void test01()
{
vector<Number> numbers;
for(size_t idx=1;idx!=30;++idx)
{
numbers.push_back(Number(idx));
}
//用mem_fn绑定成员打印函数·
std::for_each(numbers.begin(),numbers.end(),mem_fn(&Number::print));
cout<<endl;
cout<<"调用类中成员函数来删除偶数:"<<endl;
numbers.erase(remove_if(numbers.begin(),numbers.end(), mem_fn(&Number::isEven))
,numbers.end());//remove_if的用法
numbers.shrink_to_fit();
std::for_each(numbers.begin(),numbers.end(),mem_fn(&Number::print));
cout<<endl;
}
//保留质数
void test02()
{
vector<Number> numbers;
for(size_t idx=1;idx!=100;++idx)
{
numbers.push_back(Number(idx));
}
std::for_each(numbers.begin(),numbers.end(),mem_fn(&Number::print));
cout<<endl;
numbers.erase(remove_if(numbers.begin(),numbers.end(),
mem_fn(&Number::isPrime)),
numbers.end());
numbers.shrink_to_fit();
cout<<"调用类中的成员函数来删除非质数:"<<endl;
std::for_each(numbers.begin(),numbers.end(),mem_fn(&Number::print));
cout<<endl;
}
int main()
{
test01();
cout<<endl<<endl;
test02();
return 0;
}
/*
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
调用类中成员函数来删除偶数:
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
调用类中的成员函数来删除非质数:
1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
*/