在c++的标准模板库中,priority_queue是一种优先队列容器适配器,它的底层默认基于大顶堆实现,默认排序规则是元素值从大到小排列,队首元素是当前队列中的最大值。但实际开发中我们往往需要自定义排序规则,比如让队列按照元素从小到大出队,或者按照自定义结构体的某个成员排序,下面介绍几种常见的自定义排序实现方式。

使用内置的greater和less模板
priority_queue的模板参数有三个,分别是元素类型、底层容器类型、比较规则类型,默认的比较规则是less,也就是大顶堆。如果我们想要实现小顶堆,也就是元素从小到大出队,可以直接把第三个模板参数指定为greater。
需要注意的是,使用greater需要包含<functional>头文件,同时底层容器要支持随机访问,默认使用的vector是满足要求的。
#include <iostream>
#include <queue>
#include <functional>
#include <vector>
int main() {
// 定义小顶堆优先队列,元素从小到大出队
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
minHeap.push(3);
minHeap.push(1);
minHeap.push(2);
// 输出队列元素,顺序为1 2 3
while (!minHeap.empty()) {
std::cout << minHeap.top() << " ";
minHeap.pop();
}
std::cout << std::endl;
return 0;
}
自定义仿函数实现排序
当我们需要按照自定义的规则排序时,比如按照结构体的某个成员排序,或者按照复杂的逻辑判断,可以自定义仿函数作为priority_queue的比较规则。仿函数本质是重载了operator()运算符的结构体或类,priority_queue会用这个仿函数的返回值来判断元素的优先级。
仿函数的返回值需要是bool类型,当返回true时,表示第一个参数的优先级低于第二个参数,在默认的堆调整逻辑中,优先级高的元素会放在队首。
#include <iostream>
#include <queue>
#include <vector>
#include <string>
// 自定义学生结构体
struct Student {
std::string name;
int score;
};
// 自定义仿函数,按照分数从高到低排序
struct CompareStudent {
bool operator()(const Student& a, const Student& b) {
// 返回true表示a的优先级低于b,也就是分数低的优先级低
return a.score < b.score;
}
};
int main() {
// 使用自定义仿函数作为比较规则
std::priority_queue<Student, std::vector<Student>, CompareStudent> stuHeap;
stuHeap.push({"张三", 85});
stuHeap.push({"李四", 92});
stuHeap.push({"王五", 78});
// 输出顺序为李四 张三 王五
while (!stuHeap.empty()) {
Student topStu = stuHeap.top();
std::cout << topStu.name << " " << topStu.score << std::endl;
stuHeap.pop();
}
return 0;
}
重写结构体的operator<运算符
如果我们不想额外定义仿函数,也可以直接在自定义结构体中重写operator<运算符,priority_queue默认使用less比较规则,而less会调用元素的operator<来判断优先级,所以我们重写operator<就可以改变默认的排序逻辑。
这里要注意operator<的逻辑要和我们需要的排序规则对应,比如我们想要分数高的优先级高,那么当a的分数大于b的分数时,a的优先级应该更高,对应的operator<应该返回a.score < b.score吗?不对,这里需要理清楚:less的比较逻辑是,如果a < b为true,那么b的优先级比a高。所以如果我们想要分数高的优先级高,那么当a的分数比b高时,a的优先级更高,也就是a < b应该为false,所以operator<的逻辑应该是return a.score < b.score,和仿函数的逻辑是一致的。
#include <iostream>
#include <queue>
#include <vector>
#include <string>
struct Student {
std::string name;
int score;
// 重写operator<,按照分数从高到低排序
bool operator<(const Student& other) const {
// 分数高的优先级高,所以当当前对象分数小于other分数时,当前对象优先级低
return score < other.score;
}
};
int main() {
// 不需要额外指定比较规则,使用默认的less即可
std::priority_queue<Student> stuHeap;
stuHeap.push({"张三", 85});
stuHeap.push({"李四", 92});
stuHeap.push({"王五", 78});
// 输出顺序为李四 张三 王五
while (!stuHeap.empty()) {
Student topStu = stuHeap.top();
std::cout << topStu.name << " " << topStu.score << std::endl;
stuHeap.pop();
}
return 0;
}
使用lambda表达式作为比较规则
c++11之后支持lambda表达式,我们也可以把lambda表达式作为priority_queue的比较规则,不过需要注意的是,lambda表达式的类型是匿名的,所以我们需要用decltype来获取它的类型,并且在构造priority_queue的时候传入lambda表达式的实例。
#include <iostream>
#include <queue>
#include <vector>
#include <string>
struct Student {
std::string name;
int score;
};
int main() {
// 定义lambda表达式,按照分数从低到高排序
auto cmp = [](const Student& a, const Student& b) {
return a.score > b.score;
};
// 使用decltype获取lambda类型,构造时传入lambda实例
std::priority_queue<Student, std::vector<Student>, decltype(cmp)> stuHeap(cmp);
stuHeap.push({"张三", 85});
stuHeap.push({"李四", 92});
stuHeap.push({"王五", 78});
// 输出顺序为王五 张三 李四
while (!stuHeap.empty()) {
Student topStu = stuHeap.top();
std::cout << topStu.name << " " << topStu.score << std::endl;
stuHeap.pop();
}
return 0;
}
注意事项
- priority_queue的第三个模板参数是比较类型,不是比较实例,所以如果使用仿函数或者lambda,需要保证类型正确,lambda场景还需要传入实例。
- 自定义比较规则的时候要注意逻辑的正确性,避免优先级判断反了导致排序不符合预期。
- 底层容器默认是vector,也可以指定为deque,但是必须支持随机访问迭代器,不能用list。
priority_queue自定义排序greaterless仿函数修改时间:2026-06-12 06:21:18