常用算法 stl综合案例
2017-08-09 00:00
465 查看
函数对象(仿函数)
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。
分类:假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。
函数对象的作用主要是什么?STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略。
//函数对象是重载了函数调用符号的类 struct MyPrint { void operator()(int val) { cout << val << endl; } }; void test01() { //如何使用 MyPrint print01; print01(10); //重载了()操作符的类实例化的对象,可以像普通函数那样调用,可以有参数 ,可以有返回值 } //函数对象超出了普通函数的概念,可以保存函数的调用状态 struct HePrint { HePrint() { mCount = 0; } void operator()(int val) { cout << val << endl; mCount++; } int mCount; }; void test02() { HePrint print; print(10); print(20); print(30); print(40); cout << print.mCount << endl; } //函数对象可以做参数和返回值 struct OurPrint { void operator()(int val) { cout << val << endl; } }; void doBusiness(OurPrint print) { print(20); } void test03() { //函数对象做参数 doBusiness(OurPrint()); }
谓词
谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式。struct GreaterThanFive { bool operator()(int v) { return v > 5; } }; //一元谓词 void test01() { vector<int> v; for (int i = 0; i < 10; i++) { v.push_back(i); } vector<int>::iterator ret = find_if(v.begin(), v.end(), GreaterThanFive()); if (ret == v.end()) { cout << "没有找到!" << endl; } else { cout << "找到:" << *ret << endl; } } //二元谓词 struct MyCompare { bool operator()(int v1, int v2) { return v1 > v2; } }; void test02() { vector<int> v; srand((unsigned int)time(NULL)); for (int i = 0; i < 10; i++) { v.push_back(rand() % 100); } for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; //排序算法 sort(v.begin(), v.end(), MyCompare()); for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; }
内建函数对象
STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。使用内建函数对象,需要引入头文件 #include<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>//取反仿函数
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>//逻辑非
内建函数对象举例:
/*
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()
{
equal_to<int> MyEqual;
plus<int> MyPlus;
if (MyEqual(10, 20))
{
cout << "相等!" << endl;
}
else
{
cout << "不相等!" << endl;
}
cout << "MyPlus:" << MyPlus(10, 20) << endl;
}
void test02()
{
vector<int> v;
srand((unsigned int)time(NULL));
for (int i = 0; i < 10; i++)
{
v.push_back(rand() % 100);
}
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
sort(v.begin(), v.end(), greater<int>());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
函数对象适配器
#include<iostream> #include<vector> #include <functional> // 头文件 #include<algorithm> using namespace std; //函数适配器bind1st bind2nd //现在我有这个需求 在遍历容器的时候,我希望将容器中的值全部加上100之后显示出来,怎么做哇? struct myprint : public binary_function<int, int, void> { //二元函数对象 所以需要继承 binary_fucntion<参数类型,参数类型,返回值类型> void operator()(int v1, int v2) const { cout << v1 + v2 << " "; } }; void test02() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); //我们直接给函数对象绑定参数 编译阶段就会报错 //for_each(v.begin(), v.end(), bind2nd(myprint(),100)); //如果我们想使用绑定适配器,需要我们自己的函数对象继承binary_function 或者 unary_function //根据我们函数对象是一元函数对象 还是二元函数对象 for_each(v.begin(), v.end(), bind2nd(myprint(), 100)); cout << endl; //总结: bind1st和bind2nd区别? //bind1st : 将参数绑定为函数对象的第一个参数 //bind2nd : 将参数绑定为函数对象的第二个参数 //bind1st bind2nd将二元函数对象转为一元函数对象 } //函数对象适配器 not1 not2 struct myprint02 { void operator()(int v1) const { cout << v1 << " "; } }; void test03() { vector<int> v; v.push_back(2); v.push_back(1); v.push_back(5); v.push_back(4); vector<int>::iterator it = find_if(v.begin(), v.end(), not1(bind2nd(less_equal<int>(), 2))); cout << "it:" << *it << endl; sort(v.begin(), v.end(), not2(greater<int>())); for_each(v.begin(), v.end(), myprint02()); cout << endl; //not1 对一元函数对象取反 //not2 对二元函数对象取反 } //如何给一个普通函数使用绑定适配器(bind1st bind2nd)绑定一个参数? //ptr_fun void myprint04(int v1, int v2) { cout << v1 + v2 << " "; } void test04() { vector<int> v; v.push_back(2); v.push_back(1); v.push_back(5); v.push_back(4); //1 将普通函数适配成函数对象 //2 然后通过绑定器绑定参数 for_each(v.begin(), v.end(), bind2nd(ptr_fun(myprint04), 100)); cout << endl; //总结: ptr_fun 将普通函数转变为函数对象 } //mem_fun mem_fun_ref //如果我们容器中存储的是对象或者对象指针,如果能指定某个成员函数处理成员数据。 class student { public: student(string name, int age) :name(name), age(age) {} void print() { cout << "name:" << name << " age:" << age << endl; } void print2(int a) { cout << "name:" << name << " age:" << age << " a:" << a << endl; } int age; string name; }; void test05() { //mem_fun : 如果存储的是对象指针,需要使用mem_fun vector<student*> v; student* s1 = new student("zhaosi", 10); student* s2 = new student("liuneng", 20); student* s3 = new student("shenyang", 30); student* s4 = new student("xiaobao", 40); v.push_back(s1); v.push_back(s2); v.push_back(s3); v.push_back(s4); for_each(v.begin(), v.end(), mem_fun(&student::print)); cout << "-----------------------------" << endl; //mem_fun_ref : 如果存储的是对象,需要使用mem_fun_ref vector<student> v2; v2.push_back(student("zhaosi", 50)); v2.push_back(student("liuneng", 60)); v2.push_back(student("shenyang", 70)); v2.push_back(student("xiaobao", 80)); for_each(v2.begin(), v2.end(), mem_fun_ref(&student::print)); }
算法概述
算法主要是由头文件<algorithm> <functional> <numeric>组成。<algorithm>是所有STL头文件中最大的一个,其中常用的功能涉及到比较,交换,查找,遍历,复制,修改,反转,排序,合并等...
<numeric>体积很小,只包括在几个序列容器上进行的简单运算的模板函数.
<functional> 定义了一些模板类,用以声明函数对象。
常用遍历算法
/* 遍历算法 遍历容器元素 @param beg 开始迭代器 @param end 结束迭代器 @param _callback 函数回调或者函数对象 @return 函数对象 */ for_each(iterator beg, iterator end, _callback); /* transform算法 将指定容器区间元素搬运到另一容器中 注意 : transform 不会给目标容器分配内存,所以需要我们提前分配好内存 @param beg1 源容器开始迭代器 @param end1 源容器结束迭代器 @param beg2 目标容器开始迭代器 @param _cakkback 回调函数或者函数对象 @return 返回目标容器迭代器 */ transform(iterator beg1, iterator end1, iterator beg2, _callbakc)
for_each:
/* template<class _InIt,class _Fn1> inline void for_each(_InIt _First, _InIt _Last, _Fn1 _Func) { for (; _First != _Last; ++_First) _Func(*_First); } */ //普通函数 void print01(int val) { cout << val << " "; } //函数对象 struct print001 { void operator()(int val) { cout << val << " "; } }; //for_each算法基本用法 void test01() { vector<int> v; for (int i = 0; i < 10; i++) { v.push_back(i); } //遍历算法 for_each(v.begin(), v.end(), print01); cout << endl; for_each(v.begin(), v.end(), print001()); cout << endl; } struct print02 { print02() { mCount = 0; } void operator()(int val) { cout << val << " "; mCount++; } int mCount; }; //for_each返回值 void test02() { vector<int> v; for (int i = 0; i < 10; i++) { v.push_back(i); } print02& p = for_each(v.begin(), v.end(), print02()); cout << endl; cout << p.mCount << endl; } struct print03 : public binary_function<int, int, void> { void operator()(int val, int bindParam) const { cout << val + bindParam << " "; } }; //for_each绑定参数输出 void test03() { vector<int> v; for (int i = 0; i < 10; i++) { v.push_back(i); } for_each(v.begin(), v.end(), bind2nd(print03(), 100)); }
transform:
//transform 将一个容器中的值搬运到另一个容器中 /* template<class _InIt, class _OutIt, class _Fn1> inline _OutIt _Transform(_InIt _First, _InIt _Last,_OutIt _Dest, _Fn1 _Func) { for (; _First != _Last; ++_First, ++_Dest) *_Dest = _Func(*_First); return (_Dest); } template<class _InIt1,class _InIt2,class _OutIt,class _Fn2> inline _OutIt _Transform(_InIt1 _First1, _InIt1 _Last1,_InIt2 _First2, _OutIt _Dest, _Fn2 _Func) { for (; _First1 != _Last1; ++_First1, ++_First2, ++_Dest) *_Dest = _Func(*_First1, *_First2); return (_Dest); } */ struct transformTest01 { int operator()(int val) { return val + 100; } }; struct print01 { void operator()(int val) { cout << val << " "; } }; void test01() { vector<int> vSource; for (int i = 0; i < 10; i++) { vSource.push_back(i + 1); } //目标容器 vector<int> vTarget; //给vTarget开辟空间 vTarget.resize(vSource.size()); //将vSource中的元素搬运到vTarget vector<int>::iterator it = transform(vSource.begin(), vSource.end(), vTarget.begin(), transformTest01()); //打印 for_each(vTarget.begin(), vTarget.end(), print01()); cout << endl; } //将容器1和容器2中的元素相加放入到第三个容器中 struct transformTest02 { int operator()(int v1, int v2) { return v1 + v2; } }; void test02() { vector<int> vSource1; vector<int> vSource2; for (int i = 0; i < 10; i++) { vSource1.push_back(i + 1); } //目标容器 vector<int> vTarget; //给vTarget开辟空间 vTarget.resize(vSource1.size()); transform(vSource1.begin(), vSource1.end(), vSource2.begin(), vTarget.begin(), transformTest02()); //打印 for_each(vTarget.begin(), vTarget.end(), print01()); cout << endl; }
常用查找算法:
/* find算法 查找元素 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param value 查找的元素 @return 返回查找元素的位置 */ find(iterator beg, iterator end, value) /* adjacent_find算法 查找相邻重复元素 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param _callback 回调函数或者谓词(返回bool类型的函数对象) @return 返回相邻元素的第一个位置的迭代器 */ adjacent_find(iterator beg, iterator end, _callback); /* binary_search算法 二分查找法 注意: 在无序序列中不可用 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param value 查找的元素 @return bool 查找返回true 否则false */ bool binary_search(iterator beg, iterator end, value); /* find_if算法 条件查找 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param callback 回调函数或者谓词(返回bool类型的函数对象) @return bool 查找返回true 否则false */ find_if(iterator beg, iterator end, _callback); /* count算法 统计元素出现次数 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param value回调函数或者谓词(返回bool类型的函数对象) @return int返回元素个数 */ count(iterator beg, iterator end, value); /* count算法 统计元素出现次数 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param callback 回调函数或者谓词(返回bool类型的函数对象) @return int返回元素个数 */ count_if(iterator beg, iterator end, _callback);
常用排序算法
/* merge算法 容器元素合并,并存储到另一容器中 @param beg1 容器1开始迭代器 @param end1 容器1结束迭代器 @param beg2 容器2开始迭代器 @param end2 容器2结束迭代器 @param dest 目标容器开始迭代器 */ merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest) /* sort算法 容器元素排序 注意:两个容器必须是有序的 @param beg 容器1开始迭代器 @param end 容器1结束迭代器 @param _callback 回调函数或者谓词(返回bool类型的函数对象) */ sort(iterator beg, iterator end, _callback) /* sort算法 对指定范围内的元素随机调整次序 @param beg 容器开始迭代器 @param end 容器结束迭代器 */ random_shuffle(iterator beg, iterator end) /* reverse算法 反转指定范围的元素 @param beg 容器开始迭代器 @param end 容器结束迭代器 */ reverse(iterator beg, iterator end)
常用拷贝和替换算法:
/* copy算法 将容器内指定范围的元素拷贝到另一容器中 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param dest 目标容器结束迭代器 */ copy(iterator beg, iterator end, iterator dest) /* replace算法 将容器内指定范围的旧元素修改为新元素 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param oldvalue 旧元素 @param oldvalue 新元素 */ replace(iterator beg, iterator end, oldvalue, newvalue) /* replace_if算法 将容器内指定范围满足条件的元素替换为新元素 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param callback函数回调或者谓词(返回Bool类型的函数对象) @param oldvalue 新元素 */ replace_if(iterator beg, iterator end, _callback, newvalue) /* swap算法 互换两个容器的元素 @param c1容器1 @param c2容器2 */ swap(container c1, container c2)
常用算数生成算法:
/* accumulate算法 计算容器元素累计总和 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param value累加值 */ accumulate(iterator beg, iterator end, value) /* fill算法 向容器中添加元素 @param beg 容器开始迭代器 @param end 容器结束迭代器 @param value t填充元素 */ fill(iterator beg, iterator end, value)
常用集合算法:
/* set_intersection算法 求两个set集合的交集 注意:两个集合必须是有序序列 @param beg1 容器1开始迭代器 @param end1 容器1结束迭代器 @param beg2 容器2开始迭代器 @param end2 容器2结束迭代器 @param dest 目标容器开始迭代器 @return 目标容器的最后一个元素的迭代器地址 */ set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest) /* set_union算法 求两个set集合的并集 注意:两个集合必须是有序序列 @param beg1 容器1开始迭代器 @param end1 容器1结束迭代器 @param beg2 容器2开始迭代器 @param end2 容器2结束迭代器 @param dest 目标容器开始迭代器 @return 目标容器的最后一个元素的迭代器地址 */ set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest) /* set_difference算法 求两个set集合的差集 注意:两个集合必须是有序序列 @param beg1 容器1开始迭代器 @param end1 容器1结束迭代器 @param beg2 容器2开始迭代器 @param end2 容器2结束迭代器 @param dest 目标容器开始迭代器 @return 目标容器的最后一个元素的迭代器地址 */ set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
5. STL综合案例(学校演讲比赛)
学校演讲比赛介绍1)某市举行一场演讲比赛( speech_contest ),共有24个人参加。比赛共三轮,前两轮为淘汰赛,第三轮为决赛。
2)比赛方式:分组比赛,每组6个人;选手每次要随机分组,进行比赛;
第一轮分为4个小组,每组6个人。比如100-105为一组,106-111为第二组,依次类推,
每人分别按照抽签(draw)顺序演讲。当小组演讲完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
第二轮分为2个小组,每组6人。比赛完毕,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。
第三轮只剩下6个人,本轮为决赛,选出前三名。
4)比赛评分:10个评委打分,去除最低、最高分,求平均分
每个选手演讲完由10个评委分别打分。该选手的最终得分是去掉一个最高分和一个最低分,求得剩下的8个成绩的平均分。
选手的名次按得分降序排列,若得分一样,按参赛号升序排名。
用STL编程,求解这个问题
1) 请打印出所有选手的名字与参赛号,并以参赛号的升序排列。
2) 打印每一轮比赛后,小组比赛成绩和小组晋级名单
3) 打印决赛前三名,选手名称、成绩。
需求分析
//产生选手 ( ABCDEFGHIJKLMNOPQRSTUVWXYZ ) 姓名、得分;选手编号
//第1轮 选手抽签 选手比赛 查看比赛结果
//第2轮 选手抽签 选手比赛 查看比赛结果
//第3轮 选手抽签 选手比赛 查看比赛结果
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include <vector> #include <map> #include <string> #include <algorithm> #include <deque> #include <functional> #include <numeric> #include <ctime> using namespace std; /* 需求分析: 1) 产生选手 ( ABCDEFGHIJKLMNOPQRSTUVWX ) 姓名、得分;选手编号 2) 第1轮 选手抽签 选手比赛 查看比赛结果 3) 第2轮 选手抽签 选手比赛 查看比赛结果 4) 第3轮 选手抽签 选手比赛 查看比赛结果 */ class Speaker { public: string mName; //姓名 int mScore[3]; //分数 }; void createSpeaker(vector<int>&v, map<int, Speaker>&m) { string nameSeed = "ABCDEFGHIJKLMNOPQRSTUVWX"; for (int i = 0; i < 24; i++) { string name = "选手"; name += nameSeed[i]; Speaker sp; sp.mName = name; //默认三轮的分数都为0 for (int j = 0; j < 3; j++) { sp.mScore[j] = 0; } //v容器中放入的是选手编号 v.push_back(100 + i); m.insert(make_pair(100 + i, sp)); } } void speechDraw(vector<int>&v) { random_shuffle(v.begin(), v.end()); } //演讲比赛方法 void speechContest(int index, vector<int>&v1, map<int, Speaker>&m, vector<int>&v2) { //创建一个临时容器 保存小组的分数 multimap<int, int, greater<int>>groupScore; //key 是分数 value 是选手编号 , greater<int>()从大到小排序 int num = 0; for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) { num++; //评委打分 deque<int>d; for (int i = 0; i < 10; i++) { int score = rand() % 41 + 60; // 60 ~100 d.push_back(score); } //对分数进行排序 sort(d.begin(), d.end(), greater<int>()); //从大到小 //去除最高分和最低分 d.pop_back(); //最低分 d.pop_front(); //最高分 //总分 int sum = accumulate(d.begin(), d.end(), 0); //平均分 int avg = sum / d.size(); //打印选手的分数 //cout << "选手姓名" << m[*it].mName << " 获取平均分:" << avg << endl; //将分数放入到m容器中 选手身上 m[*it].mScore[index - 1] = avg; groupScore.insert(make_pair(avg, *it)); //每6人一组 进行筛选 if (num % 6 == 0) { ////查看小组比赛成绩 //cout << "小组比赛成绩如下" << endl; //for (multimap<int, int, greater<int>>::iterator mit = groupScore.begin(); mit != groupScore.end(); mit++) //{ // cout << "编号" << mit->second << " 姓名:" << m[mit->second].mName << " 成绩: " << m[mit->second].mScore[index - 1] << endl; //} //取临时容器的前三个数据 ,进入到下一轮比赛 int count = 0; for (multimap<int, int, greater<int>>::iterator mit = groupScore.begin(); mit != groupScore.end() && count < 3; mit++, count++) { v2.push_back((*mit).second); } groupScore.clear(); } } } void showScore(int index, vector<int>&v, map<int, Speaker>&m) { cout << "第" << index << "轮比赛成绩如下:" << endl; for (map<int, Speaker>::iterator it = m.begin(); it != m.end(); it++) { cout << "选手编号: " << it->first << " 选手姓名 " << it->second.mName << " 分数: " << it->second.mScore[index - 1] << endl; } cout << "晋级选手编号" << endl; for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << endl; } } int main() { srand((unsigned int)time(NULL)); //创建容器 放选手编号 vector<int>v; //创建容器 对应的放入选手编号以及具体的选手 map<int, Speaker>m; //创建24名选手 createSpeaker(v, m); //抽签 speechDraw(v); //比赛 //v2 容器存放 进入第二轮比赛的人员的编号 vector<int>v2; speechContest(1, v, m, v2); //打印成绩 showScore(1, v2, m); //第二轮比赛 speechDraw(v2); vector<int>v3; // 存放进入第三轮的人员编号容器 speechContest(2, v2, m, v3); showScore(2, v3, m); //第三轮比赛 speechDraw(v3); vector<int>v4; // 存放进入第三轮的人员编号容器 speechContest(3, v3, m, v4); showScore(3, v4, m); ////测试 //for (map<int, Speaker>::iterator it = m.begin(); it != m.end(); it++) //{ // cout << "选手姓名:" << it->second.mName << endl; //} }
相关文章推荐
- NDK-CPP语言-常用算法及综合案例
- STL中的常用算法
- ACM等算法比赛中JAVA 常用"STL"总结:TreeMap,Queue,PriorityQueue等
- 【算法专题】工欲善其事必先利其器—— C++ STL中vector(向量/不定长数组)的常用方法总结
- 算法竞赛中常用的C++ STL
- STL的常用算法
- STL算法之常用算法
- STL中的常用算法
- 浅析STL中的常用算法
- STL常用算法
- STL中常用的一些算法函数[持续更新
- C++ STL 常用算法
- STL常用的拷贝替换算术集合算法
- STL常用算法学习总结
- STL中的常用算法
- STL常用算法: remove,remove_if,remove_copy,remove_copy_if,remove系列算法和partition的区别...
- 常用STL容器及算法举例
- stl算法设计理念_预定义函数对象和函数适配器2_案例
- 常用STL容器及算法举例
- 常用STL容器及算法举例