C++STL算法(1)概述

12 篇文章 1 订阅

1. 函数对象

重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。

注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。

分类:假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。

函数对象的作用主要是什么?

STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略。

class myprint
{
public:
	myprint()
	{
		count = 0;
	}
	//对象超出普通函数概念,内存可以保存状态
	void operator()(int num)
	{
		cout<<"num "<<num<<endl;
		count++;
	}
	int count;
};
void test()
{
	myprint p;
	p(100);
	cout<<"函数调用 的次数"<<p.count<<endl;
}

在这里插入图片描述

函数对象做函数参数

class myprint
{
public:
	myprint()
	{
		count = 0;
	}
	void operator()(int num)
	{
		cout<<"num "<<num<<endl;
		count++;
	}
	int count;
};
void test()
{
	myprint p;
	p(100);
	cout<<"函数调用 的次数"<<p.count<<endl;
}
//函数对象做参数
void test1(myprint p,int num)
{
	p(num);
}
void main()
{
	//test();
	myprint p;
	test1(p,100);
	//匿名对象做参数
	test1(myprint(),30);
}

在这里插入图片描述

函数对象(仿函数)的优势

  1. 函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时问题。
  2. 函数对象超出普通函数的概念,函数对象可以有自己的状态
  3. 函数对象可内联编译,性能好。用函数指针几乎不可能
  4. 模版函数对象使函数对象具有通用性,这也是它的优势之一

谓词

谓词是指普通函数重载的operator() 返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式。

一元谓词

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

class GreaterThenFive
{
public:
	bool operator()(int num)
	{
		return num > 5;
	}
};
//一元谓词
void test01()
{
	vector<int> v;
	for (int i = 0; i < 10;i ++)
	{
		v.push_back(i);
	}
	//查找符合要求的第一个元素并返回迭代器
	 vector<int>::iterator it =  find_if(v.begin(), v.end(), GreaterThenFive());
	 if (it == v.end())
	 {
		 cout << "没有找到" << endl;
	 }
	 else
	 {
		 cout << "找到了: " << *it << endl;
	 }
}

在这里插入图片描述

二元谓词

//二元谓词
class MyCompare
{
public:
	bool operator()(int num1, int num2)
	{
		return num1 > num2;
	}
};

void test02()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(40);
	v.push_back(20);
	v.push_back(90);
	v.push_back(60);

	//默认从小到大
	sort(v.begin(), v.end());
	for_each(v.begin(),v.end(),[](int val){cout<<val<<" ";});
	cout << endl;
	cout << "----------------------------" << endl;
	//使用函数对象改变算法策略,排序从大到小
	sort(v.begin(), v.end(),MyCompare());
	//for_each 遍历算法
	for_each(v.begin(),v.end(), [](int val){cout<<val<<" ";});
	cout << endl;
}

在这里插入图片描述

内建函数对象

STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。使用内建函数对象,需要引入头文件 functional

  • 6个算数类函数对象,除了negate是一元运算,其他都是二元运算。
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 negate<T>//取反仿函数
void test()
{
	//negate 取反
	negate<int> n;
	cout<<n(10)<<endl;
	plus<int>p;
	cout<<p(10,20)<<endl;
}

在这里插入图片描述

  • 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>//小于等于
void test01()
{
	vector<int>p;
	p.push_back(10);
	p.push_back(30);
	p.push_back(40);
	p.push_back(20);
	sort(p.begin(),p.end());
	for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});
	cout<<endl;
	sort(p.begin(),p.end(),greater<int>());
	for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});
	cout<<endl;
}

在这里插入图片描述

  • 逻辑运算类运算函数,not为一元运算,其余为二元运算。
template<class T> bool logical_and<T>//逻辑与
template<class T> bool logical_or<T>//逻辑或
template<class T> bool logical_not<T>//逻辑非
void test02()
{
	vector<int>p;
	p.push_back(true);
	p.push_back(false);
	p.push_back(true);
	p.push_back(false);
	p.push_back(true);
	for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});//10101
	cout<<endl;
	vector<int>p2;
	p2.resize(p.size());
	transform(p.begin(),p.end(),p2.begin(),logical_not<bool>());
	for_each(p2.begin(),p2.end(),[](int val){cout<<val<<" ";});//01010
	cout<<endl;			
}

在这里插入图片描述

函数对象适配器

函数适配器 bind2nd() 绑定

#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<string>
using namespace std;
class myprint:public binary_function<int,int,void>
{
public:
	void operator()(int val,int num) const
	{
		cout<<"val = "<<val<<" "<<"num = "<<num<<" "<<val+num<<" "<<endl;
	}

};
//函数适配器
void test01()
{
	vector<int> p;
	for(int i = 0;i<10;i++)
	{
		p.push_back(i);
	}
	for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});
	cout<<endl;
	//函数适配器bind1st bind2nd
	//现在我有这个需求 在遍历容器的时候,我希望将容器中的值全部加上100之后显示出来,怎么做?
	//我们直接给函数对象绑定参数 编译阶段就会报错
	//for_each(v.begin(), v.end(), bind2nd(myprint(),100));
	//如果我们想使用绑定适配器,需要我们自己的函数对象继承binary_function 或者 unary_function
	//根据我们函数对象是一元函数对象 还是二元函数对象
	//bindlst bind2nd
	//1.绑定数据 bind2nd 
	//2.继承类 binary_function<参数1类型,参数2类型,返回值类型>
	//3.在函数后边加const
	//4.bind2nd(类,num)
	cout<<"bind2nd:"<<endl;
	for_each(p.begin(),p.end(),bind2nd(myprint(),100));
	cout<<"---------------------"<<endl;
	//总结:  bind1st和bind2nd区别?
	//bind1st : 将参数绑定为函数对象的第一个参数
	//bind2nd : 将参数绑定为函数对象的第二个参数
	//bind1st bind2nd将二元函数对象转为一元函数对象
	cout<<"bind1st:"<<endl;
	for_each(p.begin(),p.end(),bind1st(myprint(),100));

}

在这里插入图片描述

取反适配器 not

公有继承 :unary_function

lass greaterfive:public unary_function<int,bool>
{
public:
	bool operator()(int val) const
	{
		return val >5;
	}
};
//取反适配器
void test02()
{
	vector<int>p;
	for(int i=0 ;i<10;i++)
	{
		p.push_back(i);
	}
	//查找大于5的数
	vector<int>::iterator pos = find_if(p.begin(),p.end(),greaterfive());
	cout<<"大于5的数"<<*pos<<endl;
	//查找小于5的数  not1  一元 找出小于5  
	//vector<int>::iterator pos1 = find_if(p.begin(),p.end(),not1(greaterfive()));
	//方式二
	vector<int>::iterator pos1 = find_if(p.begin(),p.end(),not1(bind2nd(greater<int>(),5)));
	cout<<"小于5的数"<<*pos1<<endl;
	//not2 二元  排序  not2(  less<int>() ) 从大到小 相当于  greater<int>()
	sort(p.begin(),p.end(),not2(less<int>()));
	for_each(p.begin(),p.end(),[](int val){cout<<val<<" ";});
	cout<<endl;
}

在这里插入图片描述

函数指针适配器 ptr_fun

void myprint1(int val1,int val2)
{
	cout<<val1+val2<<endl;
}
//函数指针适配器   ptr_fun
void test03()
{
	vector<int> p;
	for(int i = 0;i<10;i++)
		p.push_back(i);
	// ptr_fun( )把一个普通的函数指针适配成函数对象
	for_each(p.begin(),p.end(),bind2nd(ptr_fun(myprint1),100));
}

在这里插入图片描述

成员函数适配器

//成员函数适配器
class person
{
public:
	person(string name,int age)
	{
		this->name = name;
		this->age = age;
	}
	void myperson()
	{
		cout<<name<<" "<<age<<endl;
	}
	string name;
	int age;
};
void test04()
{
	vector<person> v;
	person p1("aa",10);
	person p2("bb",11);
	person p3("cc",12);
	person p4("dd",13);
	person p5("ff",14);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
	//利用 mem_fun_ref 将Person内部成员函数适配
	for_each(v.begin(),v.end(),mem_fun_ref(&person::myperson));
	cout<<"---------------------"<<endl;
	vector<person*> v1;
	v1.push_back(&p1);
	v1.push_back(&p2);
	v1.push_back(&p3);
	v1.push_back(&p4);
	v1.push_back(&p5);
	//如果容器存放的是对象指针,  那么用mem_fun
	//如果容器中存放的是对象实体,那么用mem_fun_ref
	for_each(v1.begin(),v1.end(),mem_fun(&person::myperson));
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值