0

0

c++中如何实现自定义排序的std::set_c++比较函数仿函数用法【详解】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-01-23 17:39:08

|

659人浏览过

|

来源于php中文网

原创

std::set 默认升序,自定义排序需传入满足严格弱序的比较对象;仿函数类需重载 const operator(),参数为 const 引用,如 struct CompareById { bool operator()(const std::pair& a, const std::pair& b) const { return a.first

c++中如何实现自定义排序的std::set_c++比较函数仿函数用法【详解】

std::set 默认按升序排列,要实现自定义排序,必须在定义时传入比较对象(仿函数、lambda 或函数指针),且该比较逻辑必须满足严格弱序(strict weak ordering)——否则行为未定义,常见表现是插入失败、迭代器混乱或程序崩溃。

如何定义并传入仿函数类

仿函数即重载了 operator() 的结构体或类,它能保存状态,比函数指针更灵活。注意:必须为 const 成员函数,且参数为 const 引用(避免拷贝、符合 set 内部调用约定)。

struct CompareById {
    bool operator()(const std::pair& a,
                    const std::pair& b) const {
        return a.first < b.first; // 按 first 升序
    }
};

std::set, CompareById> mySet;

  • 类型名必须完整写出:std::set,不能省略第二个模板参数
  • 仿函数类无需实例化,std::set 内部会默认构造一个临时对象
  • 若需带状态(如逆序开关),可在构造时传参,并在成员变量中保存

使用 lambda 作为比较器的限制与写法

lambda 可读性好,但因类型唯一且不可名状,不能直接用于模板参数;必须用 decltype 推导,或封装进 std::function(不推荐,有性能开销)。最实用写法是就地声明 + decltype

立即学习C++免费学习笔记(深入)”;

Figstack
Figstack

一个基于 Web 的AI代码伴侣工具,可以帮助跨不同编程语言管理和解释代码。

下载
auto cmp = [](const int& a, const int& b) { return a % 10 < b % 10; };
std::set s1(cmp); // 必须显式传入实例!

// 错误:未提供实例,编译失败 // std::set s2; // ❌

  • lambda 必须是无捕获(capture-less),否则类型不可默认构造
  • 必须在定义容器时传入 lambda 实例(如 cmp),仅类型不足以构造 set
  • 每次定义新 set 都要重复写 decltype + 实例,不适合复用场景

常见错误:违反严格弱序导致 undefined behavior

最典型的错误是把 != 或逻辑反向写成 > 而非 ! 关系。例如以下写法会导致插入异常甚至死循环:

// ❌ 危险!不满足 irreflexivity(a < a 必须为 false)
bool operator()(const T& a, const T& b) const {
    return a.key <= b.key; // 错!应为 <
}

// ❌ 危险!不满足 transitivity(传递性难保证) bool operator()(const T& a, const T& b) const { return std::abs(a.x - b.x) < 1e-5; // 浮点近似比较禁止用于 set

  • 永远只用 定义顺序,不要用 >==
  • 浮点数慎用作 key;若必须,应转为整数倍或用固定精度量化后比较
  • 多字段比较务必用「字典序」:先比主键,相等再比次键,用 &&|| 组合,别用 ?: 简写漏掉分支

为什么不能运行时切换比较逻辑

std::set 的比较器在构造时绑定,其类型和行为已固化于红黑树结构中;修改比较规则相当于重构整棵树,标准库不支持。若需多种排序视图,正确做法是:

  • 维护原始数据容器(如 std::vector),按需用 std::sort + 不同 lambda 排序
  • 用多个 std::set 各自配不同比较器,共享同一份数据(注意同步更新)
  • 改用 std::map 存主键,再用索引 std::set 维护排序关系

仿函数不是语法糖,它是 set 正确工作的契约基础——写错一个符号,整个容器就不可靠。

相关专题

更多
Sass和less的区别
Sass和less的区别

Sass和less的区别有语法差异、变量和混合器的定义方式、导入方式、运算符的支持、扩展性等。本专题为大家提供Sass和less相关的文章、下载、课程内容,供大家免费下载体验。

202

2023.10.12

sort排序函数用法
sort排序函数用法

sort排序函数的用法:1、对列表进行排序,默认情况下,sort函数按升序排序,因此最终输出的结果是按从小到大的顺序排列的;2、对元组进行排序,默认情况下,sort函数按元素的大小进行排序,因此最终输出的结果是按从小到大的顺序排列的;3、对字典进行排序,由于字典是无序的,因此排序后的结果仍然是原来的字典,使用一个lambda表达式作为key参数的值,用于指定排序的依据。

387

2023.09.04

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

527

2023.09.20

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

197

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

190

2025.07.04

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

197

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

190

2025.07.04

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

358

2023.08.02

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号