C++ 比较器(Comparator)超详细笔记
1. 什么是比较器?
定义:一个二元函数(或函数对象),接收两个元素
a, b
,返回bool
。作用:告诉排序算法“谁应该排在前面”。
调用场景:
std::sort
/std::stable_sort
/std::set
/std::priority_queue
等。
2. 三种写法速查表
写法 | 示例 | 推荐场景 |
---|---|---|
普通函数 | bool cmp(int a,int b){return a>b;} | 快速刷题 |
仿函数 / 函数对象 | struct Cmp{bool operator()(const T&a,const T&b)const{...}}; | 需要状态、可复用 |
Lambda | sort(v.begin(),v.end(),[](const T&a,const T&b){...}); | C++11+ 最常用 |
3. 核心规则:严格弱序(Strict Weak Ordering)
必须同时满足 4 条铁律,否则 UB(未定义行为):
名称 | 用符号 < 描述 | 违反示例 |
---|---|---|
非自反 | !(a < a) 永远成立 | return a <= b; ❌ |
非对称 | a < b ⇒ !(b < a) | return a < b && b < a; ❌ |
可传递 | a < b ∧ b < c ⇒ a < c | 逻辑不自洽 |
可比较 | !(a < b) ∧ !(b < a) ⇒ a、b 等价 | 无 |
4. 升序 vs 降序模板
4.1 单关键字
// 升序
bool up(int a,int b){return a < b;}
// 降序
bool down(int a,int b){return a > b;}
4.2 多关键字(以结构体为例)
struct Node{int l,r,id;};// 升序:先 l 小,再 r 小
bool cmp_up(const Node&x,const Node&y){if(x.l!=y.l) return x.l < y.l;return x.r < y.r;
}// 降序:先 l 大,再 r 大
bool cmp_down(const Node&x,const Node&y){if(x.l!=y.l) return x.l > y.l;return x.r > y.r;
}
5. Lambda 捕获与内联
int base = 100;
sort(v.begin(), v.end(), [base](const int& x, const int& y){return abs(x - base) < abs(y - base); // 距离 base 升序
});
6. 典型错误 Top3
错误 | 后果 | 修复 |
---|---|---|
用 <= / >= | 死循环/RE | 改成 < 或 > |
修改全局变量 | UB | 保持纯函数 |
捕获引用悬空 | 野值 | 用值捕获或延长生命周期 |
7. 容器专用比较器
7.1 std::set
struct Node{int l,r;};
struct Cmp{bool operator()(const Node&a,const Node&b)const{if(a.l!=b.l) return a.l<b.l;return a.r<b.r;}
};
set<Node,Cmp> s; // 自定义排序的 set
7.2 priority_queue
auto cmp=[](const Node&a,const Node&b){return a.l>b.l;};
priority_queue<Node,vector<Node>,decltype(cmp)> pq(cmp); // 小根堆
8. 记忆口诀
“返回 bool,严格弱序;升序用
<
,降序用>
;多键先主后副,别踩 <= 坑。”
9. 一页速查卡片(可复制到代码模板)
// 单关键字升序
auto cmp1=[](int a,int b){return a<b;};// 单关键字降序
auto cmp2=[](int a,int b){return a>b;};// 多关键字升序
auto cmp3=[](const Node&x,const Node&y){if(x.l!=y.l) return x.l<y.l;if(x.r!=y.r) return x.r<y.r;return x.id<y.id;
};// 多关键字降序
auto cmp4=[](const Node&x,const Node&y){if(x.l!=y.l) return x.l>y.l;if(x.r!=y.r) return x.r>y.r;return x.id>y.id;
};