C++提高编程--仿函数、常用遍历算法(for_each、transform)详解

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;
}

输出结果为:

相关推荐
qwehjk20082 小时前
分布式计算C++库
开发语言·c++·算法
222you2 小时前
线程池的三个方法,七个参数,四个拒绝策略
java·开发语言
枫叶丹42 小时前
【HarmonyOS 6.0】ArkData 应用间配置共享:构建跨应用协作新范式
开发语言·华为·harmonyos
寻寻觅觅☆2 小时前
东华OJ-基础题-59-倒数数列(C++)
开发语言·c++·算法
我不是懒洋洋2 小时前
【数据结构】顺序表专题(详细代码及配图)
c语言·开发语言·数据结构·算法·青少年编程·visual studio
Java源码jdk2 小时前
基于javaweb和mysql的springboot校园二手书交易管理系统(java+springboot+vue+elementui+layui+mysql)
java·spring boot·mysql
Trouvaille ~2 小时前
【优选算法篇】BFS 解决最短路——寻找最优路径的真谛
c++·算法·leetcode·面试·蓝桥杯·宽度优先·最短路问题
listhi5202 小时前
基于在线优化的快速模型预测控制(Fast Online MPC)MATLAB实现
开发语言·matlab
雅俗共赏1002 小时前
医学图像重建中常用的迭代求解器分类
图像处理·算法