news 2026/6/9 20:50:59

C++ 自定义排序与优先队列运算符重载

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 自定义排序与优先队列运算符重载

写这部分代码引起的一些思考并总结

一、 优先队列的底层逻辑 (Worldview)

1. 核心矛盾:为什么用<却是“大根堆”?

std::priority_queue的行为逻辑与其命名看似矛盾,实则遵循了 STL 的一致性设计。

  • 默认属性priority_queue=Max Heap(大根堆)。

  • 默认判据std::less(即调用operator<)。

  • 判定流程

    1. 队列内部比较ab

    2. 调用a < b

    3. 若返回True,判定ba(在默认的大根堆语境下,数值大的被视为“强”)。

    4. 结果:强者 (b) 上浮至堆顶。

2. 代码

// 代码逻辑 friend bool operator<(node a,node b){ return a.z<b.z; }

解析:遵循默认逻辑。z越大,<比较时在右侧越显“强”,因此z最大的在堆顶。


二、 优先队列的三种实战写法 (Friend 友元版)

统一使用Friend (友元)写法,该写法无this指针干扰,逻辑对称,不易出错。

方案 1:大根堆 (默认流)

  • 场景:贪心求最大值、常规逻辑。

  • 效果:大的先出 (9 -> 8 -> 1)。

struct node{ int z; // 逻辑:a.z < b.z 为真 -> b 强 -> b 在顶 friend bool operator<(node a,node b){ return a.z<b.z; } }; // 声明:使用默认的大根堆机制 priority_queue<node> q;

方案 2:小根堆 (竞赛黑科技流)

  • 场景:Dijkstra 最短路、Prim、Huffman 树。

  • 原理逻辑欺骗。通过反转布尔值,让队列误以为“数值小”的才是“强者”。

  • 效果:小的先出 (1 -> 2 -> 9)。

struct node{ int z; // 逻辑反转:若 a.z > b.z,返回 true (告诉队列 b 比 a "强") // 结果:z 值小的会被判定为"强",放在堆顶 friend bool operator<(node a,node b){ return a.z>b.z; // <--- 重点:小于号里写大于逻辑 } }; // 声明:无需修改队列定义,直接用 priority_queue<node> q;

方案 3:小根堆 (工程正统流 —— 配合greater)

  • 场景:工程代码、团队协作、需要显式语义。

  • 原理替换裁判。将比较器从默认的less替换为greater

  • 要求:结构体必须重载operator>

struct node{ int z; // 逻辑:诚实重载大于号,不欺骗 friend bool operator>(node a,node b){ return a.z>b.z; } }; // 声明:显式指定 greater,并填补 vector 占位符 priority_queue<node,vector<node>,greater<node>> q;

三、greaterstd::sort的深度用法

std::greater是一个模板结构体(仿函数),其本质是调用类型的operator>

1.std::sort的默认行为

默认使用<,执行升序排列。

vector<int> v={1,5,3}; sort(v.begin(),v.end()); // 结果:1, 3, 5

2. 使用greater改为降序

传入greater实例,执行降序排列。

// 语法:greater<int>() 是构造一个临时对象 sort(v.begin(),v.end(),greater<int>()); // 结果:5, 3, 1

3. 结构体数组排序 (配合重载>)

若对自定义结构体使用greater排序,结构体内部必须重载>

struct node{ int z; // sort 降序需要 > 运算符支持 friend bool operator>(node a,node b){ return a.z>b.z; } }; vector<node> arr={{1},{5},{3}}; // 自动调用 operator>,实现 z 从大到小 sort(arr.begin(),arr.end(),greater<node>()); // 结果:5, 3, 1

对比记忆表:

容器/算法使用 greater 的效果记忆口诀
std::sort降序(Desc)大的排前面
std::priority_queue小根堆(Min Heap)小的(被视为强)在堆顶

四、 多关键字排序与自定义仿函数 (进阶)

处理复杂逻辑(如:分数优先,ID 兜底)的两种核心范式。

场景设定

struct Student{int score,id;};

目标:分数(score)高的优先;分数相同,学号(id)小的优先。

写法 A:结构体内部重载 (推荐比赛)

在一个operator<中处理所有层级逻辑。

struct Student{ int score,id; friend bool operator<(Student a,Student b){ // 第一关键字:分数。分数高的在顶(大根堆逻辑) // 若分数不相等,直接按分数定胜负 if(a.score!=b.score) return a.score<b.score; // 第二关键字:学号(仅当分数相等时执行) // 想要 id 小的在顶,需反转逻辑(小根堆逻辑) return a.id>b.id; } }; priority_queue<Student> q;

写法 B:外部仿函数 (工程推荐/解耦)

不修改结构体源码,通过定义外部“裁判类”控制排序。此方法可实现一套数据结构多种排序方式。

// 纯净数据结构 struct Student{int score,id;}; // 裁判 A:按分数优先 struct CmpScore{ bool operator()(Student a,Student b){ if(a.score!=b.score) return a.score<b.score; return a.id>b.id; } }; // 裁判 B:纯按 ID 小的优先 struct CmpID{ bool operator()(Student a,Student b){ return a.id>b.id; // 小根堆逻辑 } }; // 声明时传入具体裁判类型 priority_queue<Student,vector<Student>,CmpScore> q1; priority_queue<Student,vector<Student>,CmpID> q2;

五、 终极速查表 (多条件逻辑映射)

假设Key1为主键,Key2为次键。基于默认priority_queue(大根堆)。

需求模式逻辑方向代码写法 (friend operator <)
全大优先大顶 + 大顶if(a.k1!=b.k1)return a.k1<b.k1; return a.k2<b.k2;
全小优先小顶 + 小顶if(a.k1!=b.k1)return a.k1>b.k1; return a.k2>b.k2;
混合模式大顶 + 小顶if(a.k1!=b.k1)return a.k1<b.k1; return a.k2>b.k2;

心法

  • 想让的在顶:用<(顺应默认)。

  • 想让的在顶:用>(逻辑反转)。


六、 避坑指南

  1. 模板与对象的区别 (括号问题)

    • priority_queue需要的是类型 (Type)priority_queue<..., Cmp>(无括号)。

    • sort需要的是对象实例 (Instance)sort(..., Cmp())(有括号)。

  2. greater的依赖性

    • 使用greater<T>时,T必须重载operator>

    • 报错no match for operator>通常是因为只写了<却用了greater

  3. 引用与 Const

    • Friend (友元函数)写法:friend bool operator<(node a,node b)(值传递,简单)。

    • Member (成员函数)写法:bool operator<(const node& a) const(必须加 const,否则 STL 报错)。

    • 建议:始终坚持使用 Friend 写法,语法负担最小。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:10:49

16、Photoshop自动化操作全攻略

Photoshop自动化操作全攻略 一、创建图像PDF文件 1.1 操作步骤 从Photoshop中,点击“File”,然后选择“Browse in Bridge”打开Adobe Bridge。 点击“Window”,接着点击“Workspace”,再点击“Output”,此时Bridge会显示用于输出图像的面板。 确保选中“PDF”按钮。 …

作者头像 李华
网站建设 2026/6/8 22:46:32

29、深入探索SharePoint Web部件开发:从可视化到代码化的全面指南

深入探索SharePoint Web部件开发:从可视化到代码化的全面指南 1. 创建可视化Web部件 在开发SharePoint Web部件时,首先要确认新任务是否成功添加到任务列表中。具体操作如下: - 导航至SharePoint网站的主页。 - 点击左侧导航菜单中的“任务”列表。 当任务列表显示出来…

作者头像 李华
网站建设 2026/6/10 9:53:02

Excalidraw AI用户反馈驱动的产品迭代

Excalidraw&#xff1a;当用户反馈成为产品进化的引擎 你有没有经历过这样的场景&#xff1f;在一次远程产品评审会上&#xff0c;团队围坐在虚拟白板前&#xff0c;却因为工具太“正式”而不敢轻易下笔——线条必须笔直、形状要对齐、排版得规整。结果&#xff0c;创意还没展开…

作者头像 李华
网站建设 2026/6/8 2:12:22

Open-AutoGLM拖拽式开发十大技巧(90%工程师不知道的隐藏功能)

第一章&#xff1a;Open-AutoGLM拖拽式开发入门Open-AutoGLM 是一款面向自然语言处理任务的可视化低代码开发平台&#xff0c;专为数据科学家与工程人员设计&#xff0c;支持通过拖拽组件快速构建、训练和部署大语言模型流水线。用户无需编写大量代码&#xff0c;即可完成从数据…

作者头像 李华
网站建设 2026/6/9 10:21:26

告别问卷设计焦虑:百考通AI如何让调研变得“聪明”又高效

在数据驱动的时代&#xff0c;问卷调研已成为产品迭代、学术研究、市场洞察不可或缺的工具。然而&#xff0c;许多设计师、产品经理、科研人员甚至HR&#xff0c;都曾陷入过这样的困境&#xff1a;面对空白文档&#xff0c;不知从何问起&#xff1b;精心设计的问题&#xff0c;…

作者头像 李华
网站建设 2026/6/9 20:57:14

云原生应用性能基准测试与容量规划实战指南

1. 云原生性能测试的范式转变传统单体应用的性能测试方法在云原生架构下面临显著挑战。微服务架构、容器化部署、动态编排等特性&#xff0c;要求测试从业者重新定义性能基准测试的维度与指标。云原生性能测试不再仅仅是测量单节点的响应时间与吞吐量&#xff0c;而需要关注服务…

作者头像 李华