priority_queue默认为最大堆,通过自定义比较器可实现最小堆或复杂排序逻辑,如用std::greater或自定义functor、lambda按特定规则排序。

priority_queue
priority_queue
std::vector
std::less<T>
Compare
实现最小堆(Min-Heap) 这是最常见的自定义需求。
priority_queue
std::less<T>
a < b
a
b
b
a > b
a
b
std::greater<T>
#include <iostream>
#include <queue>
#include <vector>
#include <functional> // For std::greater
void minHeapExample() {
std::priority_queue<int, std::vector<int>, std::greater<int>> min_pq;
min_pq.push(3);
min_pq.push(1);
min_pq.push(4);
min_pq.push(1);
min_pq.push(5);
std::cout << "Min-Heap elements (smallest first): ";
while (!min_pq.empty()) {
std::cout << min_pq.top() << " ";
min_pq.pop();
}
std::cout << std::endl; // Output: 1 1 3 4 5
}为自定义类型实现排序 当你的队列里放的是自定义的结构体或类对象时,比如一个
Point
x
自定义结构体/类作为比较器(Functor) 定义一个结构体,重载
operator()
bool
priority_queue
x
operator()
a.x > b.x
#include <iostream>
#include <queue>
#include <vector>
struct MyPoint {
int x;
int y;
// 构造函数
MyPoint(int x_val, int y_val) : x(x_val), y(y_val) {}
// 用于打印
void print() const {
std::cout << "(" << x << "," << y << ")";
}
};
// 自定义比较器:根据x值,x值越大优先级越高(最大堆)
struct CompareMyPointMaxX {
bool operator()(const MyPoint& a, const MyPoint& b) const {
return a.x < b.x; // 如果a的x小于b的x,则a的优先级更低,b会排在前面
}
};
// 自定义比较器:根据x值,x值越小优先级越高(最小堆)
struct CompareMyPointMinX {
bool operator()(const MyPoint& a, const MyPoint& b) const {
return a.x > b.x; // 如果a的x大于b的x,则a的优先级更低,b会排在前面
}
};
void customObjectExample() {
std::priority_queue<MyPoint, std::vector<MyPoint>, CompareMyPointMaxX> pq_maxX;
pq_maxX.push(MyPoint(10, 20));
pq_maxX.push(MyPoint(5, 30));
pq_maxX.push(MyPoint(15, 10));
std::cout << "Custom Max-Heap by X: ";
while (!pq_maxX.empty()) {
pq_maxX.top().print();
std::cout << " ";
pq_maxX.pop();
}
std::cout << std::endl; // Output: (15,10) (10,20) (5,30)
std::priority_queue<MyPoint, std::vector<MyPoint>, CompareMyPointMinX> pq_minX;
pq_minX.push(MyPoint(10, 20));
pq_minX.push(MyPoint(5, 30));
pq_minX.push(MyPoint(15, 10));
std::cout << "Custom Min-Heap by X: ";
while (!pq_minX.empty()) {
pq_minX.top().print();
std::cout << " ";
pq_minX.pop();
}
std::cout << std::endl; // Output: (5,30) (10,20) (15,10)
}使用Lambda表达式(C++11及更高版本) 这是现代C++中非常简洁和灵活的方式。你可以在
priority_queue
auto
decltype
#include <iostream>
#include <queue>
#include <vector>
#include <functional> // For std::function (optional, but good for understanding)
struct Task {
int id;
int priority; // 优先级值,越小表示优先级越高
Task(int i, int p) : id(i), priority(p) {}
void print() const {
std::cout << "[ID:" << id << ",P:" << priority << "]";
}
};
void lambdaCustomSortExample() {
// Lambda作为比较器:根据Task的priority值,值越小优先级越高(最小堆)
// 注意:priority_queue默认是最大堆行为,所以如果希望priority值小的排在前面,
// 那么lambda应该返回 'a.priority > b.priority',表示a的优先级更低
auto cmp = [](const Task& a, const Task& b) {
return a.priority > b.priority; // 如果a的优先级值比b大,则a的优先级更低
};
// 声明priority_queue时,需要将lambda的类型作为模板参数
// 通常做法是定义一个局部变量来捕获lambda,然后用decltype获取其类型
std::priority_queue<Task, std::vector<Task>, decltype(cmp)> task_pq(cmp);
task_pq.push(Task(101, 5)); // 低优先级
task_pq.push(Task(102, 1)); // 高优先级
task_pq.push(Task(103, 3)); // 中优先级
std::cout << "Tasks by priority (smallest priority value first): ";
while (!task_pq.empty()) {
task_pq.top().print();
std::cout << " ";
task_pq.pop();
}
std::cout << std::endl; // Output: [ID:102,P:1] [ID:103,P:3] [ID:101,P:5]
}在实际项目中,我个人更倾向于使用lambda,因为它写起来快,而且如果比较逻辑只用一次,代码也更集中。但如果比较逻辑复杂或者需要在多个地方复用,一个独立的functor类会是更好的选择,因为它有名字,可读性更强。
这个问题问得好,直击核心。默认的
priority_queue
立即学习“C++免费学习笔记(深入)”;
但现实世界可没那么简单,优先级这东西,定义起来千变万化。
想想看,如果你在实现一个最短路径算法,比如Dijkstra,你需要一个优先队列来存储待处理的节点,并且每次都取出“距离源点最近”的那个节点。这里的“最近”显然是“最小”的概念,而默认的最大堆就帮不上忙了。你需要一个最小堆。
再比如,你可能在处理一个复杂的排班系统,员工有多个属性:工龄、绩效、加班意愿等等。你可能需要根据这些属性的组合来决定谁的优先级更高。比如,工龄越长优先级越高,如果工龄相同,再看绩效,绩效越高优先级越高。这种多条件、自定义逻辑的排序,默认的
int
double
所以,默认行为不是不够用,而是它只覆盖了最基础、最普遍的需求。一旦你的“优先级”定义超出了简单的数值大小,或者你需要的是“最小”而不是“最大”时,自定义排序就成了你的救星。它赋予了你对数据“排序逻辑”的完全控制权,这在解决复杂算法问题和业务逻辑时,简直是不可或缺的能力。
为复杂数据结构实现自定义排序,通常意味着你需要根据对象的多个成员变量,或者一些计算出来的属性来决定它们的相对顺序。这比简单的数值比较要精妙得多。
我一般会这么做:
明确排序规则: 这是第一步,也是最关键的一步。你需要清晰地定义“A比B优先级高”到底意味着什么。例如,对于一个
Player
选择比较器实现方式:
operator()
我们来用一个更复杂的例子:
Student
score
id
score
score
id
#include <iostream>
#include <queue>
#include <vector>
struct Student {
int id;
int score;
Student(int i, int s) : id(i), score(s) {}
void print() const {
std::cout << "[ID:" << id << ",Score:" << score << "]";
}
};
// 方法一:使用Functor
struct CompareStudent {
bool operator()(const Student& a, const Student& b) const {
// 优先比较分数:分数高的优先级高 (最大堆)
if (a.score != b.score) {
return a.score < b.score; // 如果a的分数比b低,则a的优先级更低
}
// 分数相同,比较ID:ID小的优先级高 (最小堆)
return a.id > b.id; // 如果a的ID比b大,则a的优先级更低
}
};
void complexObjectFunctorExample() {
std::priority_queue<Student, std::vector<Student>, CompareStudent> student_pq;
student_pq.push(Student(101, 90));
student_pq.push(Student(102, 95));
student_pq.push(Student(103, 90)); // 分数相同,ID不同
student_pq.push(Student(104, 85));
std::cout << "Students by Score (desc), then ID (asc): ";
while (!student_pq.empty()) {
student_pq.top().print();
std::cout << " ";
student_pq.pop();
}
std::cout << std::endl; // Output: [ID:102,Score:95] [ID:101,Score:90] [ID:103,Score:90] [ID:104,Score:85] (这里ID101在103前面,因为101的ID更小,在分数相同的情况下优先级更高)
}
// 方法二:使用Lambda表达式
void complexObjectLambdaExample() {
auto cmp_lambda = [](const Student& a, const Student& b) {
if (a.score != b.score) {
return a.score < b.score; // 分数高的优先级高
}
return a.id > b.id; // ID小的优先级高
};
std::priority_queue<Student, std::vector<Student>, decltype(cmp_lambda)> student_pq_lambda(cmp_lambda);
student_pq_lambda.push(Student(201, 88));
student_pq_lambda.push(Student(202, 92));
student_pq_lambda.push(Student(203, 88));
student_pq_lambda.push(Student(204, 92)); // 分数相同,ID不同
std::cout << "Students by Score (desc), then ID (asc) (Lambda): ";
while (!student_pq_lambda.empty()) {
student_pq_lambda.top().print();
std::cout << " ";
student_pq_lambda.pop();
}
std::cout << std::endl; // Output: [ID:202,Score:92] [ID:204,Score:92] [ID:201,Score:88] [ID:203,Score:88]
}无论是Functor还是Lambda,核心都是实现一个二元谓词(binary predicate),它接收两个对象,并返回
true
在自定义
priority_queue
常见误区:
最大堆与最小堆的逻辑混淆: 这是最普遍的。
priority_queue
top()
Compare
cmp(a, b)
true
a
b
b
a
a > b
a
cmp(a, b)
true
return a.value > b.value;
a < b
a
cmp(a, b)
true
return a.value < b.value;
std::less<int>
std::greater<int>
比较器不满足严格弱序(Strict Weak Ordering): 这是算法正确性的基石。一个有效的比较器必须满足:
cmp(x, x)
false
cmp(x, y)
true
cmp(y, x)
false
cmp(x, y)
true
cmp(y, z)
true
cmp(x, z)
true
x
y
!cmp(x, y) && !cmp(y, x)
y
z
x
z
priority_queue
参数传递效率问题: 在比较器中,如果你的自定义对象比较大,确保参数是以
const T&
T
// 错误示例:按值传递,可能导致性能问题
struct BadCompare {
bool operator()(MyBigObject a, MyBigObject b) const { // 注意这里没有const &
// ...
return a.value < b.value;
}
};
// 正确示例:按const引用传递
struct GoodCompare {
bool operator()(const MyBigObject& a, const MyBigObject& b) const {
// ...
return a.value < b.value;
}
};性能考量:
priority_queue
push
pop
O(log N)
N
log N
以上就是C++ priority_queue用法 优先队列自定义排序的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号