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 中的灵活性和重要性,它可以帮助我们定制算法的行为,满足各种不同的需求。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码文本编辑器-小白教程(Sublime text, Notepad++ Acode下载安装与使用)

代码文本编辑器-小白教程&#xff08;Sublime text, Notepad Acode下载安装与使用&#xff09; 1. Windows平台和Linux平台1.1 Sublime text1.2 Notepad 2. 安卓平台 Acode参考资料 1. Windows平台和Linux平台 1.1 Sublime text 一、安装教程 1、打开Sublime Text官网下载安…

Python知识详解【1】~{正则表达式}

正则表达式是一种用于匹配字符串模式的文本工具&#xff0c;它由一系列普通字符和特殊字符组成&#xff0c;可以非常灵活地描述和处理字符串。以下是正则表达式的一些基本组成部分及其功能&#xff1a; 普通字符&#xff1a;大多数字母和数字在正则表达式中表示它们自己。例如…

【全开源】民宿酒店预订管理系统(ThinkPHP+uniapp+uView)

民宿酒店预订管理系统 特色功能&#xff1a; 客户管理&#xff1a;该功能可以帮助民宿管理者更加有效地管理客户信息&#xff0c;包括客户的姓名、电话、地址、身份证号码等&#xff0c;并可以在客户的订单中了解客户的消费情况&#xff0c;从而更好地满足客户的需求&#xff…

【C++】数据结构:哈希桶

哈希桶&#xff08;Hash Bucket&#xff09;是哈希表&#xff08;Hash Table&#xff09;实现中的一种数据结构&#xff0c;用于解决哈希冲突问题。哈希表是一种非常高效的数据结构&#xff0c;它通过一个特定的函数&#xff08;哈希函数&#xff09;将输入数据&#xff08;通常…

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

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

【静态分析】在springboot使用太阿(Tai-e)02

参考&#xff1a;使用太阿&#xff08;Tai-e&#xff09;进行静态代码安全分析&#xff08;spring-boot篇二&#xff09; - 先知社区 本文章使用的被分析代码为GitHub - JoyChou93/java-sec-code: Java web common vulnerabilities and security code which is base on springb…

【Linux】Linux基本指令1

1.软件&#xff0c;OS&#xff0c;驱动 我们看看计算机的结构层次 1.1.操作系统 操作系统是一款做 软硬件管理 的软件 操作系统&#xff08;计算机管理控制程序&#xff09;_百度百科 (baidu.com) 操作系统&#xff08;英语&#xff1a;Operating System&#xff0c;缩写&a…

做视频号小店遇到差评怎么处理?如何规避差

大家好&#xff0c;我是喷火龙。 大家在做店的时候应该都会遇到品退、中差评这些问题&#xff0c;这对我们的店铺影响还是非常大的&#xff0c;差评过多就会影响店铺的体验分&#xff0c;从而影响店铺的流量&#xff0c;还会间接的影响商品的转化率&#xff0c;如果太低的话&a…

nginx的常用配置与命令相关硬核干货

今天小晨跟大家分享Nginx常用配置与命令相关的硬核干货&#xff0c;可以说运维工作中基本都会用到这些&#xff0c;掌握它&#xff0c;你可以不用求人&#xff01; Nginx特点 高并发、高性能&#xff1b; 模块化架构使得它的扩展性非常好&#xff1b; 异步非阻塞的事件驱动模…

如何使用java设计出一款可以玩的数独游戏!

要用Java设计一个数独游戏,你可以按照以下步骤进行: 创建一个9x9的二维数组来表示数独的棋盘。生成一个有效的数独解作为游戏的答案。随机地从答案中移除一些数字,以创建游戏的难度等级。创建一个图形用户界面(GUI)来显示棋盘和与用户的交互。检测用户输入的数字是否正确,…

流水账(CPU设计实战)——lab3

Lab3 Rewrite V1.0 版本控制 版本描述V0V1.0相对V0变化&#xff1a; 修改了文件名&#xff0c;各阶段以_stage结尾&#xff08;因为if是关键词&#xff0c;所以module名不能叫if&#xff0c;遂改为if_stage&#xff0c;为了统一命名&#xff0c;将所有module后缀加上_stage&a…

设计模式 22 访问者模式 Visitor Pattern

设计模式 22 访问者模式 Visitor Pattern 1.定义 访问者模式是一种行为型设计模式&#xff0c;它允许你在不改变已有类结构的情况下&#xff0c;为一组对象添加新的操作。它将算法与对象结构分离&#xff0c;使你能够在不修改现有类的情况下&#xff0c;为这些类添加新的操作。…

Autosar Dcm配置-特定NRC实现方式-基于ETAS软件

文章目录 前言工具配置代码编写总结 前言 项目开发过程中&#xff0c;诊断服务一般客户需求或系统需求都会有特定NRC(一般为NRC22-条件不满足)&#xff0c;也就会有特定的条件&#xff0c;需要手动加代码实现。本文介绍ETAS工具中配置的接口及简单实现。 工具配置 对于每一个…

【高阶数据结构】 B树 -- 详解

一、常见的搜索结构 适合做内查找&#xff1a; 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景。如果数据量很大&#xff0c;比如有 100G 数据&#xff0c;无法一次放进内存中&#xff0c;那就只能放在磁盘上了。 如果…

坦克飞机大战项目详解:从包结构到测试发布

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、项目初始化与包结构构建 代码案例&#xff1a; 二、资源文件与配置文件管理 代码案例…

关于NLTK

一、NLTK简介 下图来自NLTK官网&#xff1a;https://www.nltk.org/index.html NLTK&#xff0c;全称为Natural Language Toolkit&#xff0c;是一个用于处理和分析自然语言文本的Python库。它提供了一系列丰富的工具和资源&#xff0c;包括词汇资源&#xff08;如WordNet&am…

【接口自动化_05课_Pytest接口自动化简单封装与Logging应用】

一、关键字驱动--设计框架的常用的思路 封装的作用&#xff1a;在编程中&#xff0c;封装一个方法&#xff08;函数&#xff09;主要有以下几个作用&#xff1a;1. **代码重用**&#xff1a;通过封装重复使用的代码到一个方法中&#xff0c;你可以在多个地方调用这个方法而不是…

【进程空间】通过页表寻址的过程

文章目录 前言介绍页表、页框、页目录的概念页框页表页目录页表和页目录的分配 一级页表和二级页表一级页表寻址过程 二级页表寻址过程 一级页表和二级页表的对比 前言 我们知道每个进程都有属于自己的虚拟地址空间&#xff0c;且每个进程的虚拟地址都是统一的。要想通过虚拟地…

JS逆向之企名科技

文章目录 初步分析定位js编写完整代码参考文献初步分析 目标网址:企名科技 抓包分析,发现是post请求 请求代码如下: #!/usr/bin/env python3 # -*- coding: utf-8 -*- import requestsheaders = {Connection:

【主流分布式算法总结】

文章目录 分布式常见的问题常见的分布式算法Raft算法概念Raft的实现 ZAB算法Paxos算法 分布式常见的问题 分布式场景下困扰我们的3个核心问题&#xff08;CAP&#xff09;&#xff1a;一致性、可用性、分区容错性。 1、一致性&#xff08;Consistency&#xff09;&#xff1a;…