C++提高编程(六)
1 STL案例--员工分组
1.1 案例描述

1.2 实现步骤

c++
#include <iostream>
#include<vector>
#include<string>
#include<map>
#include<ctime>
using namespace std;
#define CEHUA 0
#define MEISHU 1
#define YANFA 2
class Worker {
public:
string m_Name;
int m_Salary;
};
void creatWorker(vector<Worker>&v) {
//名称种子
string nameSeed = "ABCDEFGHIJ";
for (int i = 0; i < 10; i++) {
Worker worker;
worker.m_Name = "员工";
worker.m_Name+= nameSeed[i];
worker.m_Salary = rand() % 10000 + 10000;//10000~19999
//将员工放入到容器中
v.push_back(worker);
}
}
//员工的分组
void setGroup(vector<Worker>&v,multimap<int,Worker>&m) {
for (vector<Worker>::iterator it =v.begin(); it != v.end(); it++) {
//产生随机部门的编号
int deptId = rand() % 3;//0 1 2,三个部门
//将员工插入到分组中
//key部门编号,value具体的员工
m.insert(make_pair(deptId,*it));
// cout << "姓名:" << it->m_Name << "工资" << it->m_Salary << endl;
}
}
void showWorkerByGroup(multimap<int,Worker>&m) {
cout << "策划部门:" << endl;
multimap<int,Worker>::iterator pos= m.find(CEHUA);//找到起始位置
int count = m.count(CEHUA);//统计具体人数
int index = 0;
//index<count是为了只输出一个部门的信息 ,count是这一个部门的具体人数
for (; pos != m.end() && index < count; pos++,index++) {//起始位置上面有不用写
cout << "姓名:" << pos->second.m_Name << "工资:" << pos->second.m_Salary << endl;
}
cout << "美术部门:" << endl;
pos= m.find(MEISHU);
count = m.count(MEISHU);//统计具体人数
index = 0;
for (; pos != m.end() && index < count; pos++, index++) {
cout << "姓名:" << pos->second.m_Name << "工资:" << pos->second.m_Salary << endl;
}
cout << "研发部门:" << endl;
pos = m.find(YANFA);
count = m.count(YANFA);//统计具体人数
index = 0;
for (; pos != m.end() && index < count; pos++, index++) {
cout << "姓名:" << pos->second.m_Name << "工资:" << pos->second.m_Salary << endl;
}
}
int main() {
//随机数种子
srand((unsigned int)time(NULL));
//1、创建员工
vector<Worker>vWorker;
creatWorker(vWorker);
//2、员工分组
multimap<int, Worker>mWorker;
setGroup(vWorker,mWorker);
//3、分组显示员工
showWorkerByGroup(mWorker);
//测试
//for (vector<Worker>::iterator it = vWorker.begin(); it!= vWorker.end(); it++) {
// cout << "姓名:" << it->m_Name << "工资" << it->m_Salary << endl;
//}
system("pause");
return 0;
}
//案例分析:
/*
1、先创建vector容器用来存放十名员工信息vWorker
2、然后引入一个员工类Worker里面存放属性姓名、工资
3、通过一个函数creatWorker打印员工具体的姓名和工资
4、打印员工姓名用名称种子string nameSeed="ABCDE"
5、打印工资用随机函数rand()%10000,再通过尾插法把worker信息插入容器中
6、将员工进行分组,使用multimap容器,key为索引0 1 2,表示3个部门,value表示员工信息,Worker类型
7、创建一个setGroup分组函数,传入员工工资信息和部门员工信息
8、for循环遍历部门和员工,3个部门用随机函数depId=rand()%3
9、使用map容器的make_pair插入方法将部门编号,员工工资信息传入到容器中
10、分组显示员工,提供一个分组显示函数showWorkerByGroup,传入部门员工信息
11、使用宏定义方式define定义3个部门,注意不要写分号
12、使用map容器find()函数找到部门的起始位置,查找到的员工信息用pos接收
13、使用map容器count()函数统计具体部门有几个人,用count接收
14、加一个索引值index默认为0,使用for循环遍历每个部门员工的具体信息并依次输出,只要pos不为空,后面还有数并且索引小于总数就一直输出剩下的
15、添加随机数种子使结果更加多变srand((unsigned int)time(NULL));
*/
输出结果为:

2 函数对象
2.1 函数对象
2.1.1 函数对象概念
概念:
- 重载函数调用操作符的类,其对象常称为函数对象
- 函数对象使用重载的()时,行为类似函数调用,也叫仿函数
本质:函数对象(仿函数)是一个类,不是一个函数
2.1.2 函数对象使用
特点:
- 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
- 函数对象超出普通函数的概念,函数对象内部可以有自己的状态
- 函数对象可以作为参数传递
C++
#include <iostream>
#include <string>
using namespace std;
//函数对象 (仿函数)
/*
- 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
- 函数对象超出普通函数的概念,函数对象内部可以有自己的状态
- 函数对象可以作为参数传递*/
class MyAdd {
public:
//类里面创建一个成员函数,重载()运算符
int operator()(int v1,int v2) {
return v1 + v2;
}
};
void test01() {
//1、函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
MyAdd myAdd;//myAdd就是成员对象
cout << myAdd(66, 88) << endl;
}
//2、函数对象超出普通函数的概念,函数对象内部可以有自己的状态
class MyPrint {
public:
MyPrint() {
this->count =0;//初始值
}
void operator()(string test) {
cout << test << endl;
this->count++;//每一次调用count就会++
}
int count;//内部自身的成员属性,调用的次数
//普通函数不是类,没有自己的成员,需要全局变量静态变量记录
};
void test02() {
MyPrint myPrint;//myPrint就是创建的函数对象
myPrint("abcde");
myPrint("abcde");
myPrint("abcde");
myPrint("abcde");
cout << "myPrint调用次数为:" << myPrint.count << endl;
}
//3、函数对象可以作为参数传递
void doPrint(MyPrint&mp,string test) //使用myPrint对象在函数体里实现
{
mp(test);
//原理:MyPrint类里重载了()运算符,它的对象就是函数对象,也就是仿函数,可以像函数那样被调用
//mp(test)类似于p(5),doPrint把仿函数传进去,用mp(test)调用完成打印
}
void test03() {
MyPrint myPrint;
doPrint(myPrint, "abbb");
}
int main() {
test01();
test02();
test03();
system("pause");
return 0;
}
输出结果为:

2.2 谓词
2.2.1 谓词概念
概念:
- 返回bool类型的仿函数称为谓词
- 如果operator()接受一个参数,那么叫一元谓词
- 如果operator()接受两个参数,那么叫二元谓词
2.2.2 一元谓词
C++
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
//仿函数 返回值类型为bool数据类型,称为谓词
//一元谓词
class GreaterFive {
public:
bool operator()(int val) {
return val > 5;
}
};
void test01() {
vector<int>v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
//查找容器中有没有大于5的数字
//GreaterFive()是匿名函数对象
vector<int>::iterator it= find_if(v.begin(), v.end(),GreaterFive());
if (it == v.end()) {
cout << "未找到" << endl;
}
else {
cout << "找到了大于5的数字为:" << *it << endl;
}
}
int main() {
system("pause");
return 0;
}
输出结果为:

2.2.3 二元谓词
C++
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
//二元谓词
class MyCompare {
//降序操作
public:
bool operator()(int val1,int val2) {
return val1 > val2;
}
};
void test01() {
vector<int>v;
v.push_back(88);
v.push_back(868);
v.push_back(688);
v.push_back(886);
//排序
sort(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
//sort排序规则默认升序,使用仿函数,改变算法策略,使排序规则变为降序
sort(v.begin(), v.end(),MyCompare());
cout << "改变排序后:" << endl;
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
test01();
system("pause");
return 0;
}
输出结果为:

2.3 内建函数对象
2.3.1 内建函数对象意义
概念:STL内建了一些函数对象
分类:
- 算术仿函数
- 关系仿函数
- 逻辑仿函数
用法:
- 这些仿函数所产生的对象,用法和一般函数完全相同
- 使用内建函数对象,需要引入头文件#include< functional>
2.3.2 算术仿函数
功能描述:
- 实现四则运算
- 其中negate是一元运算,其他都是二元运算
函数原型:

C++
#include <iostream>
#include<functional>
using namespace std;
//内建函数对象 算术仿函数
//negate 一元仿函数 取反仿函数
void test01() {
negate<int>n;
cout<<n(88)<<endl;//-88
}
//plus 二元仿函数 加法运算
void test02() {
plus<int>p;
cout << p(88,66) << endl;
}
int main() {
test01();
test02();
system("pause");
return 0;
}
输出结果为:

2.3.3 关系仿函数
功能描述:实现关系对比
仿函数原型:

c++
#include <iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;
//内建函数对象 关系仿函数
//大于 greater
class MyCompare {
public:
bool operator()(int val1,int val2) {
return val1 > val2;
}
};
void test01() {
vector<int>v;
v.push_back(88);
v.push_back(66);
v.push_back(99);
v.push_back(55);
sort(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
//降序
cout << "降序后:" << endl;
//sort(v.begin(), v.end(),MyCompare() );
//greater<int>() 内建函数对象,大于号
sort(v.begin(), v.end(),greater<int>() );
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
test01();
system("pause");
return 0;
}
输出结果为:

2.3.4 逻辑仿函数
功能描述:实现逻辑运算
函数原型:

C++
#include <iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;
//内建函数对象 逻辑仿函数
//逻辑非 logical_not
void test01() {
vector<bool>v;
v.push_back(true);
v.push_back(false);
v.push_back(true);
for (vector<bool>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
//利用逻辑非,将容器v搬运到容器v2中,并执行取反操作
vector<bool>v2;
v2.resize(v.size());//开辟一个和v一样大的空间
transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
test01();
system("pause");
return 0;
}
输出结果为:

3 STL常用算法
概述:
- 算法主要是由头文件< algorithm>< functional>< numeric>组成
- < algorithm>是所有STL头文件中最大的一个,范围涉及到比较、替换、查找、遍历操作、赋值、修改等等
- < numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数
- < functional>定义了一些模板类,用以声明函数对象
3.1 常用遍历算法
算法简介:
- for_each //遍历容器
- transform //搬运容器到另一个容器中
3.1.1 for_each
功能描述:实现遍历容器
函数原型:for_each(iterator beg,iterator end,_func);
- 遍历算法,遍历容器元素
- beg 开始迭代器
- end 结束迭代器
- _func 函数或者函数对象(仿函数)
C++
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
//常用遍历算法 for_each
//普通函数
void print01(int val) {
cout << val << " ";
}
//仿函数
class print02 {
public:
void operator()(int val) {
cout << val <<" ";
}
};
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(), print02());//匿名函数对象print02()
cout << endl;
}
int main() {
test01();
system("pause");
return 0;
}
输出结果为:

3.1.1 transform
功能描述:搬运容器到另一个容器中
函数原型:transform(iterator beg1,iterator end1,iterator beg2,_func);
- beg1 //原容器开始迭代器
- end1 //原容器结束迭代器
- beg2 //目标容器开始迭代器
- _func //回调函数或者函数对象(仿函数)
c++
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
//常用遍历算法 transform
class Transform {
public:
int operator()(int v) {
return v+888;
}
};
class MyPrint {
public:
void operator()(int val) {
cout << val << " ";
}
};
void test01() {
vector<int>v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
vector<int>vTarget;//目标容器
vTarget.resize(v.size());//目标容器需要提前开辟空间
transform(v.begin(), v.end(), vTarget.begin(),Transform());
for_each(vTarget.begin(), vTarget.end(),MyPrint());
cout<<endl;
}
int main() {
test01();
system("pause");
return 0;
}
输出结果为:
