0

0

C++ priority_queue自定义排序 C++优先队列仿函数写法【高阶】

冰火之心

冰火之心

发布时间:2026-02-01 19:25:22

|

977人浏览过

|

来源于php中文网

原创

priority_queue默认大根堆,改小根堆需自定义比较器:仿函数中写a>b(定义“小于”语义),且operator()必须为const成员函数并用const引用参数;lambda须通过CTAD传递,不可直接作模板参数。

c++ priority_queue自定义排序 c++优先队列仿函数写法【高阶】

priority_queue 默认是大根堆,想改成小根堆得反着写比较逻辑

很多人一上来就写 std::greater,确实能搞定基础类型的小根堆,但自定义类型或复杂排序时,std::greater 用不了——它只支持内置类型且要求重载了 operator>。真正可控的方式是传一个仿函数(functor),也就是重载了 operator() 的结构体或类。

关键点在于:priority_queue 的第三个模板参数是「比较器」,它判断「谁该排在前面」;而它的语义是“如果 comp(a, b) 为 true,说明 a 优先级低于 b,即 b 应该更靠近队首”。换句话说,这个比较器实际定义的是「小于关系」(a 小于 b → a 该沉下去),所以你写的逻辑要和直觉的“排序顺序”反过来。

  • 要实现小根堆?仿函数里写 a > b
  • 要按某个成员升序?写 a.val > b.val
  • 要先按 score 降序、再按 id 升序?写 a.score != b.score ? a.score b.id

仿函数必须是 const 成员函数,且参数用 const 引用避免拷贝

写 struct 时容易漏掉 const 限定符,导致编译失败,错误信息通常是类似 no match for call to ... (const MyComp)(const T&, const T&)。这是因为 priority_queue 内部调用比较器时传的是 const 对象,你的 operator() 也得是 const 成员函数。

另外,如果元素类型较大(比如含 vector 或 string),传值会触发不必要的拷贝,性能受损。务必用 const 引用:

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

struct Compare {
    bool operator()(const Node& a, const Node& b) const {
        return a.cost > b.cost; // 小根堆:cost 小的优先
    }
};
std::priority_queue, Compare> pq;

lambda 不能直接当模板参数,得用 function 包装或推导类型

有人想写 auto cmp = [](const auto& a, const auto& b) { return a.x > b.x; }; 然后传进 priority_queue 模板——不行。lambda 类型是独有且不可名状的,无法作为模板实参。两种可行路径:

  • std::function 包装(但有虚调用开销,不推荐用于高频场景)
  • 让编译器自动推导:C++17 起支持 std::priority_queue pq(cmp) 这种类模板参数推导(CTAD),前提是把比较器作为构造函数参数传入,而不是模板参数

后者更常用也更高效:

auto cmp = [](const Node& a, const Node& b) { return a.dist > b.dist; };
std::priority_queue, decltype(cmp)> pq(cmp);

operator

如果你的结构体自己写了 operator,但 priority_queue 又传了另一个仿函数,别指望它自动识别或报错——它完全忽略 operator,只认你模板里给的第三个参数。这点容易被忽略,尤其当调试时发现排序不对,回头检查才发现仿函数写反了,或者误以为 operator 起作用了。

更隐蔽的坑是:如果用了默认模板参数(只写前两个),比如 std::priority_queue,那它会尝试用 std::less,而这又依赖 Node::operator。一旦没定义,编译失败;一旦定义了但语义和你想要的不一致(比如你其实想要小根堆),结果就和预期相反。

所以最稳妥的做法是:永远显式写出三个模板参数,哪怕只是 std::less,也比靠默认行为强。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

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

503

2023.08.02

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

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

532

2023.09.20

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

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

282

2025.06.09

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

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

192

2025.07.04

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

208

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

191

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

56

2026.01.05

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

399

2023.07.18

go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

30

2026.01.31

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
HTML5/CSS3/JavaScript/ES6入门课程
HTML5/CSS3/JavaScript/ES6入门课程

共102课时 | 6.9万人学习

前端基础到实战(HTML5+CSS3+ES6+NPM)
前端基础到实战(HTML5+CSS3+ES6+NPM)

共162课时 | 19.2万人学习

第二十二期_前端开发
第二十二期_前端开发

共119课时 | 12.6万人学习

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

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