【第十天】C++函数对象/仿函数、谓词、适配器及常见algorithm算法

news2024/11/20 3:32:07

一、函数对象

        重载了函数调用运算符() 实例化的对象函数对象,也叫仿函数。

  • 如果函数对象 有一个参数 叫:元函数对象/仿函数
  • 如果函数对象 有二个参数 叫:元函数对象/仿函数
  • 如果函数对象 有三个及以上参数 叫:元函数对象/仿函数

注意:

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

运行结果:


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1478466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java设计模式 | 七大原则之合成复用原则

基本介绍 合成复用原则&#xff08;Composite Reuse Principle&#xff09;尽量使用合成/聚合的方式&#xff0c;而不是使用继承 设计原则核心思想总结 找出应用中可能需要变化之处&#xff0c;把他们独立出来&#xff0c;不要和那些不需要变化的代码混在一起针对接口编程&…

Ubuntu系统下DPDK环境搭建

目录 一.虚拟机配置1.添加一个网卡(桥接模式)2.修改网卡类型3.修改网卡名称4.重启虚拟机5.查看网卡信息6.dpdk配置内存巨型页 三 DPDK源代码下载和编译1.下载源代码2.解压源代码3.安装编译环境4.编译5.设置dpdk的环境变量6.禁止多队列网卡7.加载igb_uio模块8.网卡绑定9.验证测试…

Docker 入门笔记

课程地址 容器技术概述 docker能做什么&#xff1a;将应用程序代码和依赖打包为一个镜像&#xff0c;作为交付介质&#xff0c;在各种环境中部署 相比于虚拟机&#xff0c;docker 只虚拟出一个隔离的程序运行环境&#xff0c;其需要则资源大大减少 容器内的程序就好像直接运…

安装 docker 可视化工具 portainer

portainer 官方网站 https://www.portainer.io/ 一、portainer 介绍 Portainer是一款开源的容器管理平台&#xff0c;它提供了一个直观易用的Web界面&#xff0c;帮助用户管理Docker容器集群、镜像、卷等资源。Portainer 支持多种 Docker 环境&#xff0c;包括本地Docker、Sw…

EXTJS实现自定义表格

宽度自适应 width: 100%, 高度自适应 height: 100% 同时设置表格所处页面高度100% html,body,#griddemo{height: 100%;} 自定义显示的文本内容 Ext.onReady(function () {Ext.QuickTips.init()function sexText(val) {if (val 0) {return <span style"color:green…

20240229作业

1.编写链表&#xff0c;链表里面随便搞点数据&#xff0c;使用 fprintf 将链表中所有的数据&#xff0c;保存到文件中&#xff0c;使用 fscanf 读取文件中的数据&#xff0c;写入链表中 #include <stdio.h> #include <stdlib.h>// 定义链表节点结构体 struct List…

Linux系统安装使用nginx

1.编译安装Nginx服务 (1)关闭防火墙&#xff0c;将安装nginx所需要软件包传到/opt目录下 systemctl stop firewalld systemctl disable firewalld setenforce 0 将压缩包传入到/opt目录下 cd /opt wget http://nginx.org/download/nginx-1.18.0.tar.gz (2). 安装依赖…

小红书的几种赚钱方式解读

小红书的七种变现方式&#xff1a; 1.通过小红书蒲公英平台接广告&#xff0c;粉丝数量大于1000的用户可以开通。单条笔记的广告费用从几百元到几十万不等。 2.开设小红书专栏&#xff0c;粉丝数量大于1万的用户可以开通。 3.进行私域变现&#xff0c;将小红书的咨询引导到微信…

解决内嵌帆软报表出现重定向问题

最近收到反馈&#xff0c;某些程序的前端通过iframe标签内嵌finebi帆软报表时&#xff0c;出现一系列问题。 问题1: 如下图所示&#xff0c;单点登录(单点登录地址schema是https)后service地址的schema协议是http, 浏览器内核的安全策略不允许http访问https。 解决方案&#xf…

HTTP笔记(五)

个人学习笔记&#xff08;整理不易&#xff0c;有帮助点个赞&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 目录 一&#xff1a;HTTP报文首部 &#xff08;1&#xff09;HTTP请求报文 &#xff08;2&#xff09…

基于深度学习的水稻病害检测系统(含UI界面、yolov8、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8 yolov8主要包含以下几种创新&#xff1a;         1. 可以任意更换主干结构&#xff0c;支持几百种网络主干。 数据集&#xff1a;     网上下载的数据集&#x…

用户增长6步法

什么是用户增长&#xff1f; 通过痛点、产品、渠道、内容、技术、数据等要素实现用户的获取、激活、留存、变现、推荐&#xff0c;用户增长包含了产品出现前的用户增长、产品生产周期内的用户增长、产品生命周期外的用户增长三个阶段。 用户增长6步法&#xff1a;方法、模型和…

【重温设计模式】桥接模式及其Java示例

【重温设计模式】桥接模式及其Java示例 桥接模式的介绍 今天我们要探讨的&#xff0c;正是一种名为“桥接模式”的设计模式。桥接模式&#xff0c;英文名Bridge Pattern&#xff0c;是一种结构型设计模式&#xff0c;它的主要目的是将抽象部分与实现部分分离&#xff0c;使得两…

Unity(第十一部)场景

游戏有多个场景组成&#xff08;新手村&#xff0c;某某副本&#xff0c;主城&#xff09; 场景是有多个物体组成&#xff08;怪物&#xff0c;地形&#xff0c;玩家等&#xff09; 物体是有多个组件组成&#xff08;刚体组件&#xff0c;自定义脚本&#xff09; 创建场景 编辑…

77. 组合(力扣LeetCode)

文章目录 77. 组合题目描述回溯算法组合问题的剪枝操作 77. 组合 题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [ [2,4], [3,4],…

Android T 远程动画显示流程其三——桌面侧动画启动到系统侧结束流程

前言 接着前文分析Android T 远程动画显示流程其二 我们通过IRemoteAnimationRunner跨进程通信从系统进程来到了桌面进程&#xff0c;这里是真正动画播放的逻辑。 之后又通过IRemoteAnimationFinishedCallback跨进程通信回到系统进程&#xff0c;处理动画结束时的逻辑。 进入…

07-Linux部署Nginx

Linux部署Nginx 简介 NGINX是一款高性能的HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP代理服务器。它的特点包括占用内存少、并发能力强&#xff0c;因此在处理高负载和高并发的场景时表现优秀。NGINX由俄罗斯的程序设计师Igor Sysoev开发&#xff0c;最初是为俄…

LeetCode:2867. 统计树中的合法路径数目(筛质数+ DFS Java)

目录 2867. 统计树中的合法路径数目 题目描述&#xff1a; 实现代码与思路&#xff1a; 筛质数 DFS 原理思路&#xff1a; 2867. 统计树中的合法路径数目 题目描述&#xff1a; 给你一棵 n 个节点的无向树&#xff0c;节点编号为 1 到 n 。给你一个整数 n 和一个长度为 …

精读《React 高阶组件》

本期精读文章是&#xff1a;React Higher Order Components in depth 1 引言 高阶组件&#xff08; higher-order component &#xff0c;HOC &#xff09;是 React 中复用组件逻辑的一种进阶技巧。它本身并不是 React 的 API&#xff0c;而是一种 React 组件的设计理念&…

java演唱会网上订票购票系统springboot+vue

随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的交换和信息流通显得特别重要。因此&#xff0c;开发合适的基于springboot的演唱会购票系统的设计与实现成为企业必然要走…