C++:std::greater()、std::less()、自定义比较函数的规则

2023-11-15


一、结论

1.排序和建堆的效果

  • 排序:
    less<T>变成升序(从左到右遍历下标时,数组元素是从小到大
    greater<T>变成降序(从左到右遍历下标时,数组元素是从大到小
  • 建堆:
    less<T>变成大顶堆(从上层到下层,堆元素是从大到小,同层之间随便)
    greater<T>变成小顶堆(从上层到下层,堆元素是从小到大,同层之间随便)

可以看到排序和建队时,lessgreater并不是直接对应汉语意思,不能统一。其实是真正的意思是两个要比较的元素,第一个元素是否比第二个元素更小less还是更大greater。

2.解释结论

  • 排序
    上面的例子应该就看懂了吧。less就是让前一个比后一个更小;greater就是让前一个比后一个更大。谁会是a,谁会是b,是按照排序算法的。

  • 建堆
    顶堆插入一个新元素时,就是插入到最后一个叶子。在这里插入图片描述
    然后这时候整理堆内元素让堆重新满足大小顶堆。关键让新插入的结点和它的父结点进行比较,comp(新插入,它的父结点)
    大顶堆就是让父比子大,即符合less让新插入的比父结点更小;
    小顶堆就是父比子小,即符合greater让新插入的比父结点更大。

二、解析

1.比较规则:strict weak ordering

std::greater()std::less()、自定义比较函数,这些都其实是用作比较的,要遵从c++制定的比较规则。
在这里插入图片描述
需要满足三种特性要求,否则使用中会报错:

  • 反自反性:false
  • true的互斥性:truefalse(但不要求false则怎么样)
  • 传递性:truetruetrue

2.less和greater其实是什么

比如less

template <class T> struct less {
  bool operator() (const T& x, const T& y) const {return x<y;}
  typedef T first_argument_type;
  typedef T second_argument_type;
  typedef bool result_type;
};

可以看到关键就是bool operator()return x<y;

  • bool operator():要的就是这个返回值bool决定比较是否要交换。这个结果用在排序和建堆中就表示是否要交换。
  • return x<y;:可以看到其实就是使用<之类的操作符重载,这就是怎么排序的规则
    PS:但这产生了限制,基本的元素int之类的,自然可以直接比较;但复杂类型如自定义一个类,里面有多个数据,我们就还得定义重载操作符比较,要不然编译器不知道该比较什么。

3.bool返回值和比较操作符

(1)规则

bool comp(a, b)意思是:返回的值指示作为第一个参数传递的元素是否被视为在其定义的特定严格弱排序中位于第二个参数之前。

  • 返回true:表示ab(ab前)
  • 返回false:表示ba(ab`后)
op 1 op 2 2 op 1 2 op 2 结果
<
less
true,ab,不交换 false,ba,交换 false,ba,交换 数组升序、大顶堆
>
greater
false,ba,交换 true,ab,不交换 false,ba,交换 数组降序、小顶堆
<= true,ab,不交换 false,ba,交换 true,ab,不交换 代价更小的数组升序、大顶堆
>= false,ba,交换 true,ab,不交换 true,ab,不交换 代价更小的数组降序、小顶堆
== false,ba,交换 false,ba,交换 true,ab,不交换 意义不明
!= true,ab,不交换 true,ab,不交换 false,ba,交换 意义不明

(2)并不是想当然的位置交换

comp(a, b)虽然会交换ab,但你不能想当然地认为位置就该怎么样,到底数组中谁会是a,谁会是b这要看调用的算法的

比如,[a < b][6 < 1] : 0,其实是算法调用时a是6,b是1,而非看到数组中原来的顺序就想当然的a是1,b是6。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

// 重写排序方法
// 常引用const T &xxx
bool comp(const int &a, const int &b)
{
    printf("[a < b][%d < %d] : %d\n", a, b , a<b);
    return a < b;
}

int main()
{
    vector<int> v = {2, 3, 1, 6, 2, 5, 4};
    sort(v.begin(), v.end(), comp);
    for (int i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;
    return 0;
}
/*
[a < b][3 < 2] : 0
[a < b][3 < 2] : 0
[a < b][1 < 2] : 1
[a < b][6 < 1] : 0
[a < b][6 < 3] : 0
[a < b][2 < 1] : 0
[a < b][2 < 6] : 1
[a < b][2 < 3] : 1
[a < b][2 < 2] : 0
[a < b][5 < 1] : 0
[a < b][5 < 6] : 1
[a < b][5 < 3] : 0
[a < b][4 < 1] : 0
[a < b][4 < 6] : 1
[a < b][4 < 5] : 1
[a < b][4 < 3] : 0
1 2 2 3 4 5 6
*/

(3)<和<=代价证明

大致测试了一下,好像0的次数(则要交换的次数)更少,应该<=<更好吧。
同理>=>

PS:还没有证明和具体的排序算法是否有关系,应该没吧。o( ̄▽ ̄)o

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

// 重写排序方法
// 常引用const T &xxx
bool comp(const int &a, const int &b)
{
    printf("[a <= b][%d <= %d] : %d\n", a, b, a <= b);
    return a <= b;
}

int main()
{
    vector<int> v = {2, 3, 1, 6, 2, 5, 4};
    sort(v.begin(), v.end(), comp);
    for (int i = 0; i < v.size(); i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;
    return 0;
}
/*
[a <= b][3 <= 2] : 0
[a <= b][3 <= 2] : 0
[a <= b][1 <= 2] : 1
[a <= b][6 <= 1] : 0
[a <= b][6 <= 3] : 0
[a <= b][2 <= 1] : 0
[a <= b][2 <= 6] : 1
[a <= b][2 <= 3] : 1
[a <= b][2 <= 2] : 1
[a <= b][2 <= 1] : 0
[a <= b][5 <= 1] : 0
[a <= b][5 <= 6] : 1
[a <= b][5 <= 3] : 0
[a <= b][4 <= 1] : 0
[a <= b][4 <= 6] : 1
[a <= b][4 <= 5] : 1
[a <= b][4 <= 3] : 0
1 2 2 3 4 5 6
*/

三、自定义

符合两个条件:

  • bool:返回值bool
  • return x<y;:重载<之类的操作符,并且要决定比较什么元素。
  • PS:建议还要常引用,保险,禁止发生修改要比较的元素可能。

1.数组

  • 函数:使用时不加括号,加了报错
  • 类的对象:注意,排序时的类必须使用类的对象才对,直接使用类报错。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

// 重写排序函数
bool cmpfunc(const int &a, const int &b)
{
    return a < b;
    // < 升序; > 降序
}

// 模仿less、greater构建类
struct cmpClass
{
    bool operator()(const int &i, const int &j)
    {
        return (i < j);
    }
}cmpClassObject;		// 注意,排序时的类必须使用类的对象才对,使用类报错。

int main()
{
	// 使用函数
    vector<int> v1 = {2, 3, 1, 6, 2, 5, 4};
    // 使用时不加括号,加了报错
    sort(v1.begin(), v1.end(), cmpfunc);
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;
    // 1 2 2 3 4 5 6
    
    // 使用类的对象
    vector<int> v2 = {2, 3, 1, 6, 2, 5, 4};
    sort(v2.begin(), v2.end(), cmpClassObject);
    for (int i = 0; i < v2.size(); i++)
    {
        cout << v2[i] << " ";
    }
    cout << endl;
    // 1 2 2 3 4 5 6
    return 0;
}

2.优先级队列

  • 定义类时同时定义操作符重载函数:操作符重载函数,必须是具体的操作符<之类的,写()报错
  • 自定义类,自定义比较函数:操作符重载函数,必须是具体的操作符<之类的,写()报错
  • 自定义类,自定义包含比较函数的结构体:操作符重载函数,必须是写()
#include <iostream>
#include <queue>
using namespace std;

/******** 定义类时同时定义操作符重载函数 ********/
struct Node1
{
    // 要比较的元素
    int x;
    // 构造函数
    Node1(int x) { this->x = x; }
    // 操作符重载函数,必须是具体的操作符<之类的,写()报错
    bool operator<(const Node1 &b) const
    {
        // 实现less中需要的<,大顶堆
        return x < b.x;
    }
};

/******** 自定义类,自定义比较函数 ********/
struct Node2
{
    // 要比较的元素
    int x;
    // 构造函数
    Node2(int x) { this->x = x; }
};

// 操作符重载函数,必须是具体的操作符<之类的,写()报错
bool operator<(const Node2 &a, const Node2 &b)
{
    // less,大顶堆
    return a.x < b.x;
}

/******** 自定义类,自定义包含比较函数的结构体 ********/
struct Node3
{
    // 要比较的元素
    int x;
    // 构造函数
    Node3(int x) { this->x = x; }
};

struct cmpClass
{
    // 操作符重载函数,必须是写()
    bool operator()(const Node3 &a, const Node3 &b)
    {
        // less,大顶堆
        return a.x < b.x;
    }
};

int main()
{
    /******** 初始化优先级队列的对象p ********/
    // Node1类型,默认使用vector,小顶堆,同 priority_queue<Node1, vector<Node1>, less<Node1> > p;
    priority_queue<Node1> p;

    // 乱序入队
    p.emplace(1);
    p.emplace(3);
    p.emplace(2);

    // 弹出队首
    while (!p.empty())
    {
        cout << p.top().x << " ";
        p.pop();
    }
    cout << endl;
    // 3 2 1

    /******** 初始化优先级队列的对象q ********/
    // 同 priority_queue<Node2> q;
    priority_queue<Node2, vector<Node2>, less<Node2>> q;

    // 乱序入队
    q.emplace(1);
    q.emplace(3);
    q.emplace(2);

    // 弹出队首
    while (!q.empty())
    {
        cout << q.top().x << " ";
        q.pop();
    }
    cout << endl;
    // 3 2 1

    /******** 初始化优先级队列的对象r ********/
    priority_queue<Node3, vector<Node3>, cmpClass> r;

    // 乱序入队
    r.emplace(1);
    r.emplace(3);
    r.emplace(2);

    // 弹出队首
    while (!r.empty())
    {
        cout << r.top().x << " ";
        r.pop();
    }
    cout << endl;
    // 3 2 1
    return 0;
}

C++ std::优先级队列priority_queue


Reference

一个std::sort 自定义比较排序函数 crash的分析过程
关于STL中的greater()和less()
C++官网:less
C++ std::优先级队列priority_queue

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++:std::greater()、std::less()、自定义比较函数的规则 的相关文章

  • AUTOSAR代码示例

    AUTOSAR代码示例是什么 AUTOSAR代码示例是指使用AUTOSAR 汽车开放式软件体系结构 开发汽车电子系统的代码样例 它提供了一种可重复使用的解决方案 可以帮助开发人员快速实现汽车电子系统的功能
  • vue实现鼠标移入图片播放视频

    我已经写成组件 直接复制粘贴引用即可 imgOrVideo vue
  • 七步精通Python机器学习

    书籍介绍 七步精通Python机器学习 推广有奖 加关注 串个门 加好友 发消息 0 关注 1 粉丝 初中生 19 还不是VIP 贵宾
  • 将html页面部署到阿里云服务器

    阿里云服务器部署 一 购买阿里云服务器ECS并选择镜像 二 进行配置 1 配置安全组 2 宝塔Linux面板配置 三 进行部署 1 安装Nginx 2 Nginx配置 四 效果展示 一 购买阿里云服务器ECS并选择镜像 镜像 镜像市场 搜索
  • RocketMQ 简介

    本文根据阿里云 RocketMQ产品文档整理 地址 https help aliyun com document detail 29532 html userCode qtldtin2 简介 RocketMQ是由阿里捐赠给Apache的一款
  • .NET6: 开发基于WPF的摩登三维工业软件 (7)

    Python微信订餐小程序课程视频 https edu csdn net course detail 36074 Python实战量化交易理财系统 https edu csdn net course detail 35475 做为一个摩登的
  • MyBatis中JdbcType与Oracle、MySql数据类型对应关系详解

    转自 MyBatis中JdbcType与Oracle MySql数据类型对应关系详解 MyBatis 是一款优秀的持久层框架 它支持定制化 SQL 存储过程以及高级映射 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取
  • 我不需要你喜欢我

    绩效考核又开始了 大家心里都在盘算着 老大这次会给我能打多少分呢 大家各有各的心情 有人想得到肯定 也有人在想能不能过关 下面这样的场景一次又一次地在上演 场景1 在主管会议上 部门领导有些不开心地说 你们怎么打的分 A 严重超标啦 怎么没
  • Autosar软件架构

    软件架构 应用层通过 Simulink模型实现 模型的代码生成使用统一配置脚本 底层软件模块满足AUTOSAR 4 2 1标准要求 其软件架构如下图所示 软件架构 2 2 2 Com通信模块配置 BCU通过唤醒信号控制相应CAN消息的通信使
  • Vue.js 最新官方下载地址与项目导入

    目录 VUE2下载网址 VUE2使用示例 VUE3下载与使用 VUE3示例 在官网上下载vue js或者是vue min js 并用
  • shell学习笔记(3)grep -v grep

    网上查阅shell定时脚本相关代码 其中有一句grep v grep awk awk print 2 不是很理解 基础知识太薄弱 pid ps ef grep run jar grep v grep awk print 2 经查阅资料 gr
  • 【零基础 快速学Java】韩顺平 p87-101 四种进制及其相互转换、二进制运算(原码、补码、反码)、7种位运算符

    课程 p87 101 四种进制介绍 小总结 二进制0b开头 八进制0开头 十六进制0x开头 进制字母不区分大小写 直接输出十进制 如 public class temp public static void main String args
  • c++去掉多余空格

    题目 输入一个字符串 字符串中可能包含多个连续的空格 请将多余的空格去掉 只留下一个空格 输入格式 共一行 包含一个字符串 输出格式 输出去掉多余空格后的字符串 占一行 数据范围 输入字符串的长度不超过 200200 保证输入字符串的开头和
  • 什么是价值流图 (Value Stream)?示例汇总

    价值流图 VSM 是一种精益制造技术 用于分析 设计和管理将产品带给客户所需的材料和信息流 它使用标准符号系统来描述各种工作流和信息流 项目被映射为添加值或不从客户的角度添加值 目的是根除不增加价值的项目 值流映射可用于改进可重复步骤的任何
  • 前端这一刻我悟了

    早上没事 在回顾react的时候 突然悟了 发现vue 还是react组件化开发 父组件套子组件 父子组件之间相互通信 写页面样式 逻辑 发送服务器请求 学习主要学的是语法 这些语法写个两三遍就都会了 还真是代码搬运工 再就是代码写的漂亮点
  • vue项目中Echarts图表完整引入、按需加载以及修改主题色

    一 完整引入Echarts 下载安装echarts包 npm install echarts S or yarn add echarts 定义图表显示的容器 并进行渲染
  • 项目资源管理

    目录 申明 1 核心概念 2 虚拟团队 分布式团队 3 规划质量管理 3 1 1 输入 3 1 2 工具和技术 3 1 2 1 责任分配矩阵 3 1 3 输出 4 估算活动资源 4 1 1 输入 4 1 2 工具与技术 4 1 3 输出 4
  • git常用操作指令手册、持续更新....

    一 拉取远程代码到本地流程 1 新建文件夹 git bash here 初始化本地仓库 git init 2 和远程仓库建立连接 git remote add origin 远程地址 3 获取远程分支最新状态 git fetch origi

随机推荐

  • gitee删除远程仓库

    1 登录自己的gitee 2 点击仓库进行选择要删除的仓库 4 进入要删除的仓库 5 在导航栏中点击管理 强调在导航中就有了 6 在左侧的仓库设置中 再点击删除仓库 右侧删除仓库的内容浮现 7 点击删除仓库 点击确认删除 要记得输入gite
  • 【Python 1-7】Python手把手教程之——详解列表List

    列表 作者 弗拉德 来源 弗拉德 公众号 fulade me 列表 在其他语言中又被称为数组 是由一系列按特定顺序排列的元素组成 你可以创建包含字母表中所有字母 数字0 9或所有家庭成员姓名的列表 你也可以创建几个列表 把这几个列表又放在一
  • qvboxlayout布局背景色怎么设置_QT开发(二十一)——QT布局管理器

    一 布局管理器简介 QT中使用绝对定位的布局方式无法自适应窗口的变化 QT中提供了对界面组件进行布局管理的类 用于对界面组件进行管理 能够自动排列窗口中的界面组件 窗口大小变化后自动更新界面组件的大小 QLayout是QT中布局管理器的抽象
  • 西门子200SMART笔记

    第一章 PLC概述 上位机 控件库 HslControls SunnyUI 初级课程 传感器接线方式 棕色 BN 蓝色 BL 黑色 BK 信号线 NPN型 1M M 接 24V PNP型 1M M 接 0V PLC输出接线 电路图 gt 梯
  • 部队脱文档水印软件_网上下载的Word文档有水印?4种方法教你快速去水印!!...

    Hello 各位叨友们好呀 我是叨叨君 我们在网上查找资料下载文档的时候 经常会遇到一些带有水印的文件 那么该怎么把水印去除呢 今天就教大家如何快速去除Word PDF文件中的水印 方法一 设置无水印 打开word文档 点击 设计 工具 再
  • Jquery中$(function(){})

    1 在哪书写js文件 如果我们要执行一段js代码 我们该怎么办呢 1 我们可以写一个js文件 在js文件里写执行函数 然后再 进行引用 2 我们可以直接在HTML页面下 插入脚本 同样是 两种方式没什么区别 唯一的区别就是程序的解耦 所以当
  • 接口测试 —— Requests库GET请求

    Requests库GET请求是使用HTTP协议中的GET请求方式对目标网站发起请求 不带参数的GET请求请看上一篇文章的练习 1 Requests库待参数的GET请求 使用Get方法带参数请求时 是params 参数字典 而不是data 参
  • new出的对象数组必须要用delete[]删除,而普通数组和结构数组delete和delete[]都一样

    为何new出的对象数组必须要用delete 删除 而普通数组delete和delete 都一样 CrtMemBlockHeader 温馨提示 该文所有测试没有特殊说明都是在Debug模式下 用的是VS2010编译器
  • JavaScript的数组塌陷

    关注微信公众号 大前端私房菜 回复暗号 面试宝典 即可免费领取107页前端面试题 什么是数组塌陷 当数组执行删除单元操作时 被删除单元 之后的单元 会前移 进而顶替被删除单元 出现在被删除单元的位置上 造成数组长度减少的情况 这样的现象称为
  • 修改Intelij IDEA的maven下载地址为国内阿里云镜像

    1 win7环境 默认情况下在用户目录的 m2下自己新建setting文件 m2 settings xml 2 settings xml文件内容为 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  • 【数学建模】2023 深圳杯 & 东三省 数学建模 B 题 :电子资源版权保护问题(含源代码 & 最终论文)

    文章目录 一 题目介绍 二 问题的解答 2 1 问题一 2 1 1 图像的预处理 2 1 2 LSB的方法 stegano库测试 2 1 3 LSB 方法建模 2 2 问题二 2 3 问题三 2 3 1 方法与步骤概述 2 3 2 基于DC
  • Python的编码风格是怎么样的?核心要点有这些

    Python因为其简洁明了的编码风格和以缩进划分作用域的规则让其在编码时对风格的统一是有非常严格的要求的 下文就将详细说明python的编码风格是怎么样的 现在你将要写更长 更复杂Python代码 是时候讨论一下代码风格了 大多数语言都能以
  • 【学习笔记】经典目标检测算法

    定义 目标检测任务的目标是找到图像中的所有感兴趣区域 并确定这些区域的位置和类别 目标检测领域的深度学习方法主要分为两大类 两阶段式 Two stage 目标检测算法和单阶段式 One stage 目标检测算法 两步模型有独立地 显式地提取
  • 7-19 支票面额 (15分)

    7 19 支票面额 15分 一个采购员去银行兑换一张y元f分的支票 结果出纳员错给了f元y分 采购员用去了n分之后才发觉有错 于是清点了余额尚有2y元2f分 问该支票面额是多少 输入格式 输入在一行中给出小于100的正整数n 输出格式 在一
  • 华硕天选一代无线网卡断网

    问题描述 本人笔记本是华硕天选1 型号为FA506IV 最近无线网卡经常断开 重连就显示无法连接网络 关闭WLAN再重开 发现一个网络都搜不到 打开任务管理器 查看性能一栏 WLAN这个选项没有了 打开设备管理器 查看网络适配器 Realt
  • 图的应用--Prim算法

    图的应用 Prim算法 Prim算法是一种基于顶点的贪心算法 从起始顶点出发 每次迭代选择当前可用的最小权值边 然后把边上依附的其他顶点加入最小生成树 prim算法可以称为 加点法 比较适合稠密图 算法思想 设G V E 是一个加权连通图
  • Python2.7网络通信socket和串口通信serial多线程同时实现

    Python2 7下多线程网络通信socket和串口通信serial同时进行 最近在写网络通信TCP IP读取数据和串口通信读取发送数据 之前写了单线程的然后这次尝试多线程实现 当然我是写的网络通信的服务端 话不多说贴上代码 coding
  • CentOS 7安装zabbix-agent 5.0报错:依赖检测失败:libpcre.so.0()(64bit)/获取GPG密钥失败解决

    报错信息 root localhost wget https mirrors tuna tsinghua edu cn zabbix zabbix 5 0 rhel 6 x86 64 zabbix agent 5 0 0 1 el6 x86
  • Conda、pip(安装torch等深度学习包、搭建运行环境)解决PackagesNotFoundError: The following packages....

    第一步 先创建一个环境 这个需要用conda来 conda create n 名字 python 版本号 这时可能会出问题 PackagesNotFoundError The following packages are not avail
  • C++:std::greater()、std::less()、自定义比较函数的规则

    文章目录 一 结论 1 排序和建堆的效果 2 解释结论 二 解析 1 比较规则 strict weak ordering 2 less和greater其实是什么 3 bool返回值和比较操作符 1 规则 2 并不是想当然的位置交换 3 lt