C++ STL 中的自定义比较:深入理解相等和等价

STL 中的自定义比较、相等和等价

  • 一、简介
  • 二、STL 的排序部分
  • 三、STL 的未排序部分
  • 四、比较元素
  • 五、实现比较器
  • 六、总结

一、简介

本文主要讨论了在 STL 中使用自定义比较函数,以及比较操作中的相等和等价概念。

有如下的代码:

std::vector< std::pair<int, std::string> > v1 = ... // v1 填充数据
std::vector< std::pair<int, std::string> > v2 = ... // v2 填充数据
std::vector< std::pair<int, std::string> > results;std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());std::set_difference(v1.begin(), v1.end(),v2.begin(), v2.end(),std::back_inserter(result),compareFirst);

这里有两个由两个排序向量 v1v2 表示的数据集,对其应用 std::set_differencestd::set_difference 将其输出写入 resultsstd::back_inserter 确保所有输出都被 push_backresults 中。

但是,有一个特殊之处:使用 std::set_difference 时提供了一个自定义比较运算符 compareFirst

默认情况下,std::set_difference 使用 std::pair 上的默认比较来比较元素(它比较 pair 的第一个和第二个元素),而在这里希望使用 compareFirst 仅根据第一个元素比较 paircompareFirst 不在 STL 中,因此需要自己实现它。

在开始实现之前,已经得到一个有趣的结论。即使 std::set_difference 要求其输入已排序,也可以使用它(或任何针对排序元素的算法)基于与用于排序的比较器不同的比较器(称之为 C),前提是元素也根据此比较器 C 排序。例如,在例子中,使用一个 std::set_difference,它根据 pair 的第一个元素进行比较,尽管这些 pair 已经根据其第一个和第二个元素进行了排序。但由于它们必须按第一个元素排序,所以这样做完全没问题。

现在实现一下 compareFirst。第一个版本:

bool compareFirst(const std::pair<int, std::string>& p1, const std::pair<int, std::string>& p2)
{return p1.first == p2.first; // 不是最终代码,存在bug!
}

实际上,这个实现根本不会给出预期的结果。但为什么呢?毕竟,set_difference 应该检查给定元素是否等于另一个集合中的另一个元素,对吧?

至少可以说,这看起来很不自然。

二、STL 的排序部分

这部分包括关联容器(std::mapstd::multimapstd::setstd::multiset),因为它们的元素已排序。

一些算法也属于此类别,因为它们假设它们操作的元素已排序:例如 std::set_differencestd::includesstd::binary_search

三、STL 的未排序部分

这部分包括序列容器(std::vectorstd::liststd::dequestd::string),因为它们的元素不一定排序。

属于此类别的算法是不需要其元素排序的算法,例如 std::equalstd::countstd::find

四、比较元素

在 C++ 中有两种表达“a 与 b 相同”的方式:

  • 自然方式:a == b。这称为相等。相等基于 operator==
  • 另一种方式:a 不小于 b 并且 b 不小于 a,所以 !(a<b) && !(b<a)。这称为等价。等价基于 operator<

然后自然会产生关于等价性的两个问题。

等价与相等有什么不同?

对于像 int 这样的简单类型,实际上对于实践中的大多数类型来说,等价性确实与相等性相同。但有一些特别的类型,它们的等价性与相等性不同,例如:不区分大小写的字符串。

为什么用如此牵强的方式表达一件简单的事情?

当算法比较集合中的元素时,很容易理解必须只有一种比较它们的方式(拥有多个比较器很麻烦,并且会造成不一致的风险)。因此,需要在基于 operator==operator< 进行比较之间做出选择。

在 STL 的排序部分,已经做出了选择:根据排序的定义,元素必须使用 operator<(或自定义的 (operator<) 类函数)进行比较。另一方面,未排序部分没有这个限制,可以使用自然的 operator==

五、实现比较器

STL 的未排序部分使用 operator== 来执行比较,而排序部分使用 operator<。自定义比较运算符必须遵循此逻辑。

现在了解了如何为 std::set_difference 实现自定义运算符 compareFirst,它操作排序元素:

bool compareFirst(const std::pair<int, std::string>& p1, const std::pair<int, std::string>& p2)
{return p1.first < p2.first; // 正确的,与 STL 兼容的代码。
}

六、总结

本文深入探讨了 STL 中自定义比较函数的使用,以及比较操作中相等和等价的概念。

  • STL 被分为排序部分和非排序部分,分别使用 operator<operator== 进行比较。
  • 自定义比较函数必须遵循 STL 的比较规则,才能与排序部分的算法兼容。
  • 相等和等价在大多数情况下是相同的,但对于一些特殊类型,例如不区分大小写的字符串,它们可能存在差异。

理解这些概念对于高效使用 STL 至关重要。例如,在使用 std::set_difference 等算法时,需要根据数据的排序方式和比较需求,选择合适的自定义比较函数,才能获得预期的结果。

此外,本文还强调了自定义比较函数在 STL 中的灵活性和重要性,它可以帮助我们定制算法的行为,满足各种不同的需求。

在这里插入图片描述

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

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

相关文章

【C++】牛客——活动安排

✨题目链接&#xff1a; AB31 活动安排 ✨题目描述 给定&#x1d45b;个活动&#xff0c;每个活动安排的时间为[&#x1d44e;&#x1d456;,&#x1d44f;&#x1d456;)。求最多可以选择多少个活动&#xff0c;满足选择的活动时间两两之间没有重合。 ✨输入描述: 第一行…

北交所的股票交易佣金最低是多少?万分之二算低的吗?

北交所的佣金目前最低是万分之二&#xff0c;不过只有少数证券公司是这个标准。普通股票佣金万1&#xff0c;融资利率是4.0%~5.0%&#xff01; 北交所佣金一般是万分之6&#xff0c;北交所全称是北京证券交易所&#xff0c;是一家公司制交易所&#xff0c;北交所的佣金比普通股…

【JVM底层原理,JVM架构详解】

1. JVM简介 1.1 什么是JVM? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 主流虚拟机: 虚拟机名称介绍HotSpotOracle/Sun JDK和OpenJDK都使用HotSPo…

人大金仓python驱动安装指引

最好使用虚拟环境&#xff0c;避免各种路径异常问题 在指定目录下创建虚拟环境 python3 -m venv myenv myenv可以是一个路径&#xff0c;当前命令会创建一个叫myenv的目录&#xff0c;目录里放的是虚拟环境所需的可执行文件 激活虚拟环境 source myenv/bin/activate 退出虚…

2024-05-28 服务器开发-不同vs版本的std::string的访问出错问题-记录

摘要: 有一个dll库是使用vs2010编译的, 使用这个dll动态库的工程是vs2019. 这个dll动态库返回一个结构体&#xff0c;其中有个成员使用了std::string。但是遇到了std::string的成员显示被赋值为NULL的情况。 本文对进行分析, 重点在于追踪问题的思路。 问题描述: dll使用vs20…

保护“第二生命线”,科技守护颈椎健康

脊柱支撑着人体重量&#xff0c;汇集着众多血管神经&#xff0c;素有“人体第二生命线”之称。在如今快节奏的时代&#xff0c;人们生活方式也在发生着变化&#xff0c;长期低头看手机、伏案久坐等不良生活习惯引发脊柱健康问题&#xff0c;且呈现年轻化趋势。目前&#xff0c;…

【加密与解密(第四版)】第十二章笔记

第十二章 注入技术 12.1 DLL注入方法 在通常情况下&#xff0c;程序加载 DLL的时机主要有以下3个&#xff1a;一是在进程创建阶段加载输入表中的DLL&#xff0c;即俗称的“静态输人”;二是通过调用 LoadLibrary(Ex)主动加载&#xff0c;称为“动态加载”&#xff1b;三是由于系…

核心三:正确的停止线程

3、核心三&#xff1a;正确的停止线程 3.1 如何正确的停止线程 3.1.1 原理介绍&#xff1a;使用interrupt来通知&#xff0c;而不是强制 线程中断的机制&#xff1a;一个线程来通知要中断线程&#xff08;你好&#xff0c;你现在应该停止了&#xff09;最后的决定是由要中断…

第十四届蓝桥杯c++研究生组

A 关键思路是求每个十进制数的数字以及怎么在一个数组中让判断所有的数字次数相等。 求每个十进制的数字 while(n!0){int x n%10;//x获取了n的每一个位数字n/10;}扩展&#xff1a;求二进制的每位数字 &#xff08;注意&#xff1a;进制转换、1的个数、位运算&#xff09; x…

主干网络篇 | YOLOv8更换主干网络之MobileNeXt | 新一代移动端模型MobileNeXt来了!

前言:Hello大家好,我是小哥谈。MobileNeXt是由微软研究院提出的一种高效的卷积神经网络结构,它在保持模型轻量级的同时,能够获得较高的性能。MobileNeXt采用了一种称为Inverted Residuals with Linear Bottlenecks(IRL)的结构,通过深度可分离卷积和快捷连接来减少模型的…

[Android]将私钥(.pk8)和公钥证书(.pem/.crt)合并成一个PKCS#12格式的密钥库文件

如下&#xff0c;我们有一个platform.pk8和platform.x509.pem。为了打包&#xff0c;需要将私钥&#xff08;.pk8&#xff09;和公钥证书&#xff08;可能是.pem或.crt文件&#xff09;合并成一个PKCS#12 格式的密钥库文件 1.准备你的私钥和证书文件 确保你有以下两个文件&…

设计模型-系统架构师(三)

1、按照《中华人民共和国著作权法》的权利保护期&#xff0c;署名权和修改权 是永久保护的。 发表权、使用权和获取报酬权 保护期限 作者终生和死后的50年。 2、&#xff08;重要&#xff09;面向对象的分析模型主要由 顶层架构图、用例与用例图和&#xff08;&#xff09;构成…

2024年物理化学与工程技术发展国际会议(ICPCETD 2024)

全称&#xff1a;2024年物理化学与工程技术发展国际会议&#xff08;ICPCETD 2024&#xff09; 会议网址:http://www.icpcetd.com 会议时间: 2024.06.30 截稿时间&#xff1a;2024.06.21 会议地点: 上海 投稿邮箱&#xff1a;icpcetd_info163.com 投稿标题&#xff1a;ArticleT…

前端开发框架Angular

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Angular概述 Angular是由Google开发并维护的一款开源前端开发框架。它最初被设计为用于构建单页面应用&#xff08;SPA&#xff09;&#xff0c;但随着版本的更新和发展&am…

刚接触抖店并开通了个体店,怎么快速起店呢?运营思路参考如下

我是王路飞。 如果你刚接触抖店&#xff0c;并且开通了个体店&#xff0c;但不知道如何做店的话。 其实很简单&#xff0c;抖店的流程并没有这么复杂。 电商的核心无非就是产品&#xff0c;抖店的运营也都是围绕产品展开的。 我给你们说下抖店的运营思路你们可以作为参考&a…

【Real】[Flask]SSTI

文章目录 前言一、题目解读二、解题过程三、知识点Flask是什么SSTI是什么SSTI是如何形成的易于利用的类payload是什么 探索类型和类层次结构和方法 前言 温馨提示&#xff1a;看到哪里不懂直接跳到知识点部分&#xff0c;理解完再回到解题过程。 一、题目解读 题目是[Flask]S…

如何使用Docker快速运行Firefox并实现远程访问本地火狐浏览器

文章目录 1. 部署Firefox2. 本地访问Firefox3. Linux安装Cpolar4. 配置Firefox公网地址5. 远程访问Firefox6. 固定Firefox公网地址7. 固定地址访问Firefox Firefox是一款免费开源的网页浏览器&#xff0c;由Mozilla基金会开发和维护。它是第一个成功挑战微软Internet Explorer浏…

【Linux学习】进程间通信 (3) —— System V (1)

下面是有关进程通信中 System V 的相关介绍&#xff0c;希望对你有所帮助&#xff01; 小海编程心语录-CSDN博客 目录 1. System V IPC 1. 消息队列 msg 消息队列的使用方法 1.1 消息队列的创建 1.2 向消息队列发送消息 1.3 从消息队列接收消息 1.4 使用msgctl函数显式地…

科技查新是什么?一文了解!

本文主要解答 1、什么是科技查新&#xff1f; 2、科技查新有哪些作用&#xff1f; 3、科技查新一般应用于什么地方&#xff1f; 4、在哪能出具正规查新报告&#xff1f; 5、科技查新流程是怎样的&#xff1f; 带着这些问题阅读这篇文章相信一定会有收获&#xff01;干活内…

【启程Golang之旅】运算符与流程控制讲解

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…