一、函数对象
重载了函数调用运算符()的类 实例化的对象叫函数对象,也叫仿函数。
- 如果函数对象 有一个参数 叫:一元函数对象/仿函数
- 如果函数对象 有二个参数 叫:二元函数对象/仿函数
- 如果函数对象 有三个及以上参数 叫:多元函数对象/仿函数
注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重裁了"()"操作符使得它可以像函数一样调用。(仿函数概念由来)
二、谓词
返回值为bool类型的普通函数或仿函数 都叫谓词。
如果谓词 有一个参数 叫:一元谓词
如果谓词 有二个参数 叫:二元谓词
一般没有多元谓词
1、一元谓词
用于查找:(头文件algorithm提供find_if算法策略)
2、二元谓词
用于排序: (头文件algorithm提供sort算法策略)
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
bool myGreater(int n1,int n2)
{
return n1>n2;
}
class MyGreater
{
public:
bool operator()(int n1,int n2)
{
return n1>n2;
}
};
void printVectorInt(vector<int> v)
{
vector<int>::iterator it;
for(it=v.begin();it!=v.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
void test()
{
//sort排序
vector<int> v;
v.push_back(3);
v.push_back(1);
v.push_back(5);
v.push_back(2);
v.push_back(4);
printVectorInt(v);
sort(v.begin(),v.end());//顺序
printVectorInt(v);
//倒序
//sort(v.begin(),v.end(),myGreater);
sort(v.begin(),v.end(),MyGreater());
printVectorInt(v);
}
int main(int argc, char *argv[])
{
test();
return 0;
}
关键代码及运行结果:
三、内建函数对象
定义:系统提供好的 函数对象。(实质是类模板)
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>//取反仿函数
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>//小于等于
逻辑运算类运算函数,not为一元运算,其余为二元运算:
- template<class T> bool logical_and<T>//逻辑与
- template<class T> bool logical_or<T>//逻辑或
- template<class T> bool logical_not<T>//逻辑非
一元谓词查找用内建函数实现:
将二元谓词排序用内建函数对象实现:
四、适配器
适配器 为算法 提供接口。
1、函数对象 适配器
2、函数指针适配器 ptr_fun
3、成员函数 作为适配器 mem_fun_ref
4、取反适配器
not1函数:一元取反
not2函数: 二元取反
五、 常见算法
头文件:#include<algorithm>,适用于随机访问迭代器。
1、遍历算法
(1)for_each遍历算法
遍历容器元素:for_each(iterator beg, iterator end, _callback);
param beg 开始迭代器
param end 结束迭代器
param _callback 函数回调或者函数对象
return 函数对象
(2)transform算法
将指定容器区间元素搬运到另一容器中:
transform(iterator beg1, iterator end1, iterator beg2, _callbakc);
注意 : transform 不会给目标容器分配内存,所以需要我们提前分配好内存
param beg1 源容器开始迭代器
param end1 源容器结束迭代器
param beg2 目标容器开始迭代器
param _cakkback 回调函数或者函数对象
return 返回目标容器迭代器
2、查找算法
(1)find算法
查找元素:find(iterator beg, iterator end, value)
param beg 容器开始迭代器
param end 容器结束迭代器
param value 查找的元素
return 返回查找元素的位置
查找基本类型数据:
查找自定义类型数据:
#include <iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class Person
{
friend void test();
private:
int num;
string name;
public:
Person(){}
Person(int num,string name)
{
this->num=num;
this->name=name;
}
//重载==提供比较策略
bool operator==(const Person &ob)
{
return ((ob.name==this->name)&&(ob.num==this->num));
}
};
void test()
{
vector<Person> v;
v.push_back(Person(3,"tom"));
v.push_back(Person(1,"bob"));
v.push_back(Person(5,"张三"));
v.push_back(Person(2,"小明"));
v.push_back(Person(1,"小红"));
vector<Person>::iterator ret;
//find 查找自定义数据类型 需要重载==
ret=find(v.begin(),v.end(),Person(5,"张三"));
if(ret!=v.end())
{
cout<<"找到元素:"<<(*ret).num<<" "<<(*ret).name<<endl;
}
}
int main(int argc, char *argv[])
{
test();
return 0;
}
主函数代码及运行结果:
(2)find_if算法 条件查找
find_if(iterator beg, iterator end, _callback);
param beg 容器开始迭代器
param end 容器结束迭代器
param callback 回调函数或者谓词(返回bool类型的函数对象)
return bool 查找返回true 否则false
(3)adjacent_find算法 查找相邻重复元素
adjacent_find(iterator beg, iterator end, _callback);
param beg 容器开始迭代器
param end 容器结束迭代器
param _callback 回调函数或者谓词(返回bool类型的函数对象)
return 返回相邻元素的第一个位置的迭代器
(4)binary_search算法 二分查找法
bool binary_search(iterator beg, iterator end, value);
注意: 必须在有序序列中使用,在无序序列中不可用。
param beg 容器开始迭代器
param end 容器结束迭代器
param value 查找的元素
return bool 查找返回true 否则false
(5)count算法 统计元素出现次数
count(iterator beg, iterator end, value);
param beg 容器开始迭代器
param end 容器结束迭代器
param value 要统计的元素
return int返回元素个数
(6)count_if算法 按条件统计元素出现次数
param beg 容器开始迭代器
param end 容器结束迭代器
param callback 回调函数或者谓词(返回bool类型的函数对象)
return int返回元素个数
3、排序算法
(1)merge算法 容器元素合并
merge算法 容器元素合并,并存储到另一容器中:
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterat or dest)
注意:两个容器必须是有序的,合并后的容器仍然有序,目标容器需预留空间。
param beg1 容器1开始迭代器
param end1 容器1结束迭代器
param beg2 容器2开始迭代器
param end2 容器2结束迭代器
param dest 目标容器开始迭代器
(2)sort算法 容器元素排序
sort算法 容器元素排序 :sort(iterator beg, iterator end, _callback)
param beg 容器1开始迭代器
param end 容器1结束迭代器
param _callback 回调函数或者谓词(返回bool类型的函数对象)
(3)random_shuffle算法 对指定范围内的元素随机调整次序
random_shuffle(iterator beg, iterator end)
param beg 容器开始迭代器
param end 容器结束迭代器
(4)reverse算法 反转指定范围的元素
reverse(iterator beg, iterator end)
param beg 容器开始迭代器
param end 容器结束迭代器
4、拷贝替换算法
(1)copy算法
copy算法 将容器内指定范围的元素拷贝到另一容器中
copy(iterator beg, iterator end, iterator dest)
param beg 容器开始迭代器
param end 容器结束迭代器
param dest 目标起始迭代器
copy提升:
(2)replace算法
将容器内指定范围的旧元素修改为新元素:
replace(iterator beg, iterator end, oldvalue, newvalue)
param beg 容器开始迭代器
param end 容器结束迭代器
param oldvalue 旧元素
param oldvalue 新元素
(3)replace_if算法
replace_if算法 将容器内指定范围满足条件的元素替换为新元素
replace_if(iterator beg, iterator end, _callback, newvalue)
param beg 容器开始迭代器
param end 容器结束迭代器
param callback函数回调或者谓词(返回Bool类型的函数对象)
param oldvalue 新元素
(4)swap算法 互换两个容器的元素
swap(container c1, container c2)
param c1容器
param c2容器2
5、算数生成算法
(1)accumulate算法 计算容器元素累计总和
accumulate(iterator beg, iterator end, value)
param beg 容器开始迭代器
param end 容器结束迭代器
param value追加值 (求和完后 + value)
(2)fill算法 向容器中填满元素
fill(iterator beg, iterator end, value)
param beg 容器开始迭代器
param end 容器结束迭代器
param value 填充元素
6、 集合算法
(3)set_intersection求两个set集合的交集
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
注意:两个集合必须是有序序列
param beg1 容器1开始迭代器
param end1 容器1结束迭代器
param beg2 容器2开始迭代器
param end2 容器2结束迭代器
param dest 目标容器开始迭代器
return 目标容器的最后元素下一位置的迭代器地址
(2)set_union算法 求两个set集合的并集
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
注意:两个集合必须是有序序列
param beg1 容器1开始迭代器
param end1 容器1结束迭代器
param beg2 容器2开始迭代器
param end2 容器2结束迭代器
param dest 目标容器开始迭代器
return 目标容器的最后元素下一位置的迭代器地址
(3)set_difference算法 求两个set集合的差集
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end 2, iterator dest)
注意:两个集合必须是有序序列
param beg1 容器1开始迭代器
param end1 容器1结束迭代器
param beg2 容器2开始迭代器
param end2 容器2结束迭代器
param dest 目标容器开始迭代器
return 目标容器的最后一个元素的迭代器地址
六、综合案例
某市举行一场演讲比赛,共有24个人参加。比赛共三轮,前两轮为淘汰赛,第三轮为决 赛。
比赛方式:分组比赛,每组6个人;选手每次要随机分组,进行比赛;
- 第一轮分为4个小组,每组6个人。比如编号为: 100-123. 整体进行抽签 (draw)后顺序演讲。当小组演讲完后,淘汰组内排名最后的三个选手,然后 继续下一个小组的比赛。
- 第二轮分为2个小组,每组6人。比赛完毕,淘汰组内排名最后的三个选手,然后继续下一 个小组的比赛。
- 第三轮只剩下1组6个人,本轮为决赛,选出前三名。
比赛评分:10个评委打分,去除最 低、最高分,求平均分每个选手演讲完由10个评委分别打分。该选手的最终得分是去掉一 个最高分和一个最低分,求得剩下的8个成绩的平均分。选手的名次按得分降序排列。
需求分析: 1) 产生选手 ( ABCDEFGHIJKLMNOPQRSTUVWX ) 姓名、得分;选手编 号
实现思路:需要把选手信息、选手得分信息、选手比赛抽签信息、选手的晋级信息保存在容器中,需要涉及到各个容器的选型。选手可以设计一个类Speaker(姓名和得分)所有选手的编号可以单独放在一个vector容器中,做抽签用-所有选手编号和选手信息,可以放在map容器内。
#include <iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<stdlib.h>
#include<time.h>
#include<deque>
using namespace std;
class player
{
friend void play(int index,vector<int> &v, map<int,player> &m, vector<int> &v1);
private:
int num;
string name;
float score[3];
public:
player(){}
player(int num,string name)
{
this->name=name;
this->num=num;
}
};
void createPlayer(vector<int> &v,map<int,player> &m)
{
string seedname="ABCDEFGHIJKLMNOPQRSTUVWX";
for(int i=0;i<24;i++)
{
string tmpname="选手";
tmpname+=seedname[i];
int num=i;
v.push_back(num);
m.insert(make_pair(num,player(num,tmpname)));
}
}
void play(int index,vector<int> &v,map<int,player> &m,vector<int> &v1)
{
//选手编号随机分组
srand(time(NULL));
random_shuffle(v.begin(),v.end());
multimap<float,int,greater<float>> mul;//存放每组的分数‐‐编号
vector<int>::iterator it=v.begin();
int count=0;
cout<<"-------第"<<index<<"轮比赛-------"<<endl;
//每名选手比赛
for(;it!=v.end();it++)
{
count++;
//定义deque容器 存放评委打分
deque<float> d;
int i=0;
for(;i<10;i++)
{
d.push_back((float)(rand()%41+60));
}
//排序
sort(d.begin(),d.end());
//去掉最高、最低分
d.pop_front();
d.pop_back();
//求平均分
float avg=accumulate(d.begin(),d.end(),0)/d.size();
//将平均分 赋值给m中选手
m[*it].score[index-1]=avg;
mul.insert(make_pair(avg, *it));
if(count%6==0)//刚好一组
{
cout<<"\t第"<<count/6<<"组的晋级名单:"<<endl;
int i=0;
multimap<float,int,greater<float>>::iterator mit=mul.begin();
for(;i<3;i++,mit++)
{
v1.push_back( (*mit).second);
cout<<"\t\t"<<(*mit).second<<" "<<(*mit).first<<endl;
}
cout<<"\t第"<<count/6<<"组的得分情况:"<<endl;
mit=mul.begin();
for(int i=0;i<6;i++,mit++)
{
int num=(*mit).second;
cout<<"\t\t"<<num<<" "<<m[num].name<<" "<<m[num].score[index-1]<<endl;
}
mul.clear();
}
}
}
void test()
{
vector<int> v;
map<int,player> m;
//创建选手
createPlayer(v,m);
vector<int> v1;//存放晋级选手的编号
play(1,v,m,v1);
vector<int> v2;//存放晋级选手的编号
play(2,v1,m,v2);
vector<int> v3;//存放晋级选手的编号
play(3,v2,m,v3);
}
int main(int argc, char *argv[])
{
test();
return 0;
}
运行结果: