C++自定义排序方式
注意
以下内容为Chatgpt生成后整理
在 C++ 中,自定义比较函数(通常是一个函数或者函数对象)和仿函数(函数对象)都可以用于自定义排序规则或比较方式,但它们的实现方式和使用方法有所不同。
1. 自定义比较函数
自定义比较函数是指一个普通的函数,它用于定义如何比较两个对象。通常,这个函数有两个参数,返回值是一个布尔值,表示这两个对象之间的比较结果。
特点:
- 形式:自定义比较函数通常是一个独立的普通函数。
- 使用方式:它可以作为参数传递给排序算法(如
std::sort)或数据结构(如std::priority_queue)等,定义对象的排序或比较规则。 - 返回类型:一般返回一个
bool类型,表示是否满足某种条件(例如:a < b,返回true表示a小于b)。
示例:
|
在这个示例中,compare 函数定义了一个比较规则,std::sort 采用该规则对 vector<int> 进行排序。
注意
在 C++ 的排序函数(比如sort)中,这个compare函数的作用是告诉排序算法:当compare(a, b)返回true时,a会排在b前面。
优点:
- 简单直接。
- 易于理解和使用。
缺点:
- 无法存储状态。如果需要在比较中保存某些信息或行为(如计数、配置等),就不太适合使用普通函数。
2. 仿函数(函数对象)
仿函数是通过重载 operator() 来创建的对象,使得这个对象能够像函数一样被调用。换句话说,仿函数是一种行为类似于函数的类或结构体。它通常用于需要自定义行为且需要存储状态的场景。
特点:
- 形式:仿函数是一个类或结构体,类中重载了
operator(),使得对象可以像函数一样调用。 - 使用方式:和普通函数一样,仿函数也可以作为参数传递给算法或数据结构,但它可以保存状态(例如:比较次数、特定的配置信息等)。
- 返回类型:和自定义比较函数一样,仿函数通常返回
bool类型,但它可以执行更加复杂的操作。
示例:
|
在这个示例中,Compare 结构体重载了 operator(),使得它成为一个仿函数。我们在 std::sort 中使用了 Compare(),它会像一个函数一样进行排序。
优点:
- 可以保存状态。仿函数是类,因此可以在类中定义成员变量,保存一些额外的状态信息,提供更强的灵活性。
- 可以定义复杂的比较行为,除了简单的比较,还可以使用成员函数、静态变量等。
缺点:
- 相比普通函数,仿函数的实现相对复杂,需要定义一个类或结构体并重载
operator()。
3. 自定义比较函数与仿函数的区别
| 特点 | 自定义比较函数 | 仿函数(函数对象) |
|---|---|---|
| 实现形式 | 普通函数 | 类或结构体,重载 operator() |
| 使用方式 | 作为参数传递给算法或数据结构(如 std::sort) |
作为参数传递给算法或数据结构(如 std::sort) |
| 存储状态 | 无法存储状态 | 可以存储状态,通过成员变量保存信息 |
| 灵活性 | 较简单,适用于简单的比较 | 更灵活,适合需要额外状态或行为的场景 |
| 适用场景 | 适合简单的比较和排序场景 | 适合需要动态行为或存储状态的复杂场景 |
4.各个容器和算法支持自定义比较器的区别
1. std::priority_queue(优先队列)
priority_queue<T, vector<T>, Compare> |
- 传入参数:
Compare(a, b)传入的是 父节点a,子节点b。 - 返回值含义:
- 如果
Compare(a, b) == true,表示a的优先级低于b,因此a会排在b的下方。 - 默认是
std::less<T>(最大堆),要实现小顶堆,用std::greater<T>或自定义Compare。
- 如果
📌 示例(小顶堆):
struct Compare { |
行为:
pq.top()返回最小的元素。- 最小堆(小顶堆):堆顶是最小的元素。
2. std::sort(排序)
sort(begin, end, Compare) |
- 传入参数:
Compare(a, b)传入的是 相邻的a和b。 - 返回值含义:
- 如果
Compare(a, b) == true,表示a应该排在b前面。 - 默认是
std::less<T>(升序),如果Compare(a, b) == a > b,则是降序排序。
- 如果
📌 示例(降序排序):
struct Compare { |
行为:
- 返回
true代表a应该在b前面。 - 影响整个排序规则。
3. std::set / std::map(有序容器)
set<T, Compare> |
- 传入参数:
Compare(a, b)传入的是 两个元素(set的值 或map的键)。 - 返回值含义:
- 如果
Compare(a, b) == true,表示a应该排在b前面。 - 如果
Compare(a, b) == false && Compare(b, a) == false,说明a == b,此时set/map认为元素已存在,不会插入。 - 默认是
std::less<T>(升序),如果Compare(a, b) == a > b,则是降序存储。
- 如果
📌 示例(降序 set):
struct Compare { |
📌 示例(自定义 map 排序):
struct Compare { |
行为:
set/map的顺序由Compare控制。- 必须保证
Compare是严格弱序(Strict Weak Ordering),否则行为未定义。
4. std::multiset / std::multimap(可重复有序容器)
multiset<T, Compare> |
- 规则和
set/map一样,但允许重复元素。 - 多个相等的元素会按照
Compare规定的顺序存储。
📌 示例(降序 multiset):
multiset<int, greater<int>> ms = {1, 3, 2, 3, 2}; |
行为:
- 内部按
greater<int>存储,顺序为{3, 3, 2, 2, 1}。
5. std::unordered_set / std::unordered_map
unordered_set和unordered_map不能使用Compare,因为它们使用哈希函数 (hash<T>) 进行存储,而不是比较器。- 但可以自定义
hash和operator==以影响存储方式。
📌 示例(自定义哈希):
struct MyHash { |
行为:
unordered_set允许使用自定义hash影响存储,但不支持Compare影响顺序。
总结
| STL 容器 / 算法 | Compare(a, b) 作用 |
true 的含义 |
默认比较器 |
|---|---|---|---|
priority_queue<T, vector<T>, Compare> |
传入 (父节点, 子节点) | a 优先级低于 b(a 在 b 下面) |
std::less<T>(大顶堆) |
sort(begin, end, Compare) |
传入 (左元素, 右元素) | a 在 b 前面 |
std::less<T>(升序) |
set<T, Compare> |
传入 (元素1, 元素2) | a 在 b 前面 |
std::less<T>(升序) |
map<Key, Value, Compare> |
传入 (键1, 键2) | a 在 b 前面 |
std::less<T>(升序) |
multiset<T, Compare> |
传入 (元素1, 元素2) | a 在 b 前面 |
std::less<T>(升序) |
multimap<Key, Value, Compare> |
传入 (键1, 键2) | a 在 b 前面 |
std::less<T>(升序) |
unordered_set / unordered_map |
不能用 Compare,只能用 hash<T> |
- | hash<T> |
priority_queue:true=a优先级低(更靠下)。sort/set/map:true=a应该在b前面。