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

一、函数对象

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

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

注意:

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.mzph.cn/news/709641.shtml

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

相关文章

windows下基于docker-desktop 安装 mysql 5.7

0.背景 docker-desktop v4.27.1Windows 11 22H2 docker-desktop 需要wsl的支持,一般win11新机子都默认开启了,安装docker-desktop 一路next即可.win10老版本需要自行安装开启wsl.一个小建议是,如果你的win10安装wsl时各种错误无法解决,建议升级到win11大概率解决,本人亲身经历…

K8S存储卷与PV,PVC

一、前言 Kubernetes&#xff08;K8s&#xff09;中的存储卷是用于在容器之间共享数据的一种机制。存储卷可以在多个Pod之间共享数据&#xff0c;并且可以保持数据的持久性&#xff0c;即使Pod被重新调度或者删除&#xff0c;数据也不会丢失。 Kubernetes支持多种类型的存储卷…

Three.js-03Vite打包入门

1.安装 说明&#xff1a;创建文件以后&#xff0c;按照提示进行操作。如cd文件夹&#xff0c;npm i ,npm run dev等操作。 npm create vitelatest 2.安装three npm i three.js 4.打开npm官网 说明:搜索three第三方库。按照案例进行操作。 5.修改App.vue文件 <script set…

2024年随想

今天2月最后一天了&#xff0c;明天就是3月了&#xff0c;年也正式算过完了吧。我也到了新的单位工作。新的开始新的工作。很高兴下个月&#xff0c;我自己的小孩就要出生了&#xff0c;我也要正式成为一名父亲了。2024年加油。

Win10Ubuntu22.04+FRP0.54搭建内网穿透

1. 下载FRP安装包&#xff0c;FRP为开源软件&#xff0c;在GITHUB可以直接下载&#xff08;选择当前最新的0.54版本&#xff09;&#xff1a;https://github.com/fatedier/frp/releases 下载windows版本安装包&#xff1a;frp_0.54.0_windows_amd64.zip 下载Linux版本安装包&am…

swift 监听状态栏frame变化

针对状态栏高度做一些操作 import UIKitclass ViewController: UIViewController {private var statusBarFrameObservation: NSKeyValueObservation?override func viewDidLoad() {super.viewDidLoad()if let statusBarManager UIApplication.shared.windows.first?.window…

golang的接口探索

1、接口是什么? 在Go语言中,接口是一种类型。抽象地定义了一组方法签名,但不实现这些方法。接口类型指定了一个值应该有哪些方法,因此,任何具有这些方法的类型都自动满足该接口。 在 Go 语言的语义上,只要某个类型实现了所定义的一组方法集,则就认为其就是同一种类型,…

Rocky Linux 运维工具 chown

一、chown 的简介 chown 用于更改文件或目录的所有者&#xff08;owner&#xff09;身份。通过 chown 命令&#xff0c;可以将文件或目录的所有权转移给另一个用户或组&#xff0c;从而控制对该文件或目录的访问和权限。 二、chown 的参数说明 使用语法&#xff1a;chown [新所…

算法刷题day19

目录 引言一、因数平方和二、爬树的甲壳虫三、改变数组元素 引言 这几道题主要都是考察数学&#xff0c;如果数学学的不好&#xff0c;推不出来公式&#xff0c;或者是你的数学思维不好都是做不出来的&#xff0c;所以说数学真的很重要&#xff0c;不过其实能考的数学也就那几…

手撕LRU缓存——LinkedHashMap简易源码

题目链接&#xff1a;https://leetcode.cn/problems/lru-cache/description/?envTypestudy-plan-v2&envIdtop-100-liked 原理非常简单&#xff0c;一个双端链表配上一个hash表。 首先我们要知道什么是LRU就是最小使用淘汰。怎么淘汰&#xff0c;链表尾部就是最不常用的直接…

Google大模型Bard更名Gemini,现在实力如何?(VS gpt系列)

名人说&#xff1a;一花独放不是春&#xff0c;百花齐放花满园。——《增广贤文》 作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、简要介绍1、Gemini是什么&#xff1f;2、主要特点3、Gemini的版本4、应用潜力5、…

zookeeper启动报错

启动zookeeper报错 从报错中可以看到 Invalid config, exiting abnormally 意思是&#xff1a;配置无效&#xff0c;异常退出 在往上看是没有zoo.cof这个配置文件 2024-02-27 14:47:03,285 [myid:] - ERROR [main:o.a.z.s.q.QuorumPeerMain99] - Invalid config, exiting…

基于AMDGPU-ROCm的深度学习环境搭建

在风起云涌的AI江湖&#xff0c;NVIDIA凭借其CUDA生态和优秀的硬件大杀四方&#xff0c;立下赫赫战功&#xff0c;而另一家公司AMD也不甘示弱&#xff0c;带着他的生态解决方案ROCm开始了与不世出的NVIDA的正面硬钢&#xff0c;"ROCm is the answer to CUDA", AMD官网…

2月29日,每日信息差

&#x1f396; 素材来源官方媒体/网络新闻 &#x1f384; 小米汽车门店开建&#xff0c;首批销售网点至少六十家 &#x1f30d; 中国民航局&#xff1a;到2035年我国将建成航空运输强国 &#x1f30b; 中国石化&#xff1a;已累计建成充电站超6000座 &#x1f381; ofo 被强制执…

前端监控及搭建前端监控

前端监控怎么做&#xff1f; 前端也需要监控&#xff1f;技术人不可忽视的前端监控最全指南 一.前端监控的目的 为什么要进行前端监控&#xff1f; 是一种用于捕获&#xff0c;分析和报告网站或应用程序中存在异常&#xff0c;错误和性能问题的方法。通过监控&#xff0c;…

java界面代码

package day02;import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;public class lei4j extends JFrame implements ActionListener {//创建文本框JTextField tiaomu new JTextField(40);//创建密码文本框JPasswordField JK ne…

Java——数组的定义与使用

目录 一.数组的基本概念 1.什么是数组 2.数组的创建及初始化 3.数组的使用 二.数组是引用类型 1.初始JVM的内存分布 2.基本类型变量与引用类型变量的区别 3.再谈引用变量 4.认识 null 三.数组的应用场景 1.保存数据 2.作为函数的参数 2.1参数传基本数据类型 2.…

centos8安装xrdp

centos8安装xrdp 1、安装桌面服务2、关闭selinux3、安装xrdp4、创建root用户4.1 创建普通用户4.2 更改为超级用户 5、连接 xrdp是可以提供远程桌面服务&#xff0c;让linux系统也可以像windows一样&#xff0c;进行远程连接 1、安装桌面服务 Linux服务器没有安装桌面环境。如…

学习vue3第二节(使用vite 创建vue3项目)

使用vite 创建vue3项目 node 安装请移步 node官网&#xff1a; https://nodejs.p2hp.com/ node 版本控制 请移步 nvm官网&#xff1a;https://nvm.uihtm.com/ vite 生成vue项目完整版 请移步 vite官网&#xff1a;https://cn.vitejs.dev/ 1、使用 npm 或者 yarn 创建vue3 项目…

nwjs做自动化测试

分别是2个常用的自动化测试化框架 GitHub - nwutils/nw-selenium-javascript-example: An example of end-to-end testing with Selenium for NW.js apps via JavaScript GitHub - nwutils/nw-puppeteer-example: An example of using NW.js via Puppeteer. 看习惯使用哪个&…