在做leetcode题目时很多题都需要使用优先队列(堆),并需要使用自定义数据类型、自定义有限队列的排序方式。本文对priority_queue的自定义排序方式做了总结。本文可能并不能覆盖所有自定义方式,若读者有建议或本文存在纰漏,请在本文下留言,不胜感激。
Priority queues are a type of container adaptors, specifically designed such that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.
优先队列是一类容器适配器,该容器满足:按照某种严格弱序排列,该容器的第一个元素总是所有元素中最大(最小)的。
priority_queue 的模板参数:
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
T
:元素类型。
Container
:低层存储容器类型,默认为vector< T >类型。
Compare
:两个参数且返回值为bool类型的双参判断式,默认为less< T >判断式。
假设使用priority_queue存储自定义类型Node,Node数据结构如下:
struct Node{
int size;
int price;
}
不同的自定义排序方式如下:
即重载数据类型Node的 < 、>运算符,使得Node类型的对象可以使用<,>符号进行比较。代码如下:
struct Node {
int size;
int price;
// 重载<运算符
bool operator<(const Node &b) const {
return this->size == b.size ? this->price > b.price : this->size < b.size;
}
};
int main() {
priority_queue<Node> priorityQueue;
for (int i = 0; i < 5; i++) {
priorityQueue.push(Node{i, 5 - i});
}
while (!priorityQueue.empty()) {
Node top = priorityQueue.top();
cout << "size:" << top.size << " price:" << top.price << endl;
priorityQueue.pop();
}
return 0;
}
输出结果为:
size:4 price:1
size:3 price:2
size:2 price:3
size:1 price:4
size:0 price:5
由于priority_queue中默认使用less
假如需要使用
priority_queue<Node, vector<Node>, greater<Node>> priorityQueue;
初始化优先队列,还需要对Node的>符号进行重载,代码如下:
struct Node {
int size;
int price;
// 重载>运算符
bool operator>(const Node &b) const {
return this->size == b.size ? this->price < b.price : this->size > b.size;
}
};
另外,也可以使用其他重载方式对Node数据类型的<、>符号进行重载,这是c++中运算符重载的内容,这里就不再展开了。
需要注意的是:
在Node结构体内进行运算符重载使,重载函数一定要声明const类型,不然编译不通过。
使用仿函数(函数对象)作为Compare双参判断式。代码如下:
struct Node {
int size;
int price;
};
class Cmp {
public:
bool operator()(const Node &a, const Node &b) {
return a.size == b.size ? a.price > b.price : a.size < b.size;
}
};
int main() {
priority_queue<Node, vector<Node>, Cmp> priorityQueue;
for (int i = 0; i < 5; i++) {
priorityQueue.push(Node{i, 5 - i});
}
while (!priorityQueue.empty()) {
Node top = priorityQueue.top();
cout << "size:" << top.size << " price:" << top.price << endl;
priorityQueue.pop();
}
return 0;
}
输出结果为:
size:4 price:1
size:3 price:2
size:2 price:3
size:1 price:4
size:0 price:5
需要注意的是:使用仿函数对优先队列进行自定义排序,需要在声明priority_queue对象时显式地定义Container类型和Compare类型,即:
priority_queue<Node, vector<Node>, Cmp> priorityQueue;
c++中lamdbda表达式相关的知识也很多,这里不讨论lambda表达式中详细的细节问题,如有需要可以参考C++ lambda表达式。
使用lambda表达式对priority_queue自定义排序的代码如下:
auto cmp = [](const Node &a, const Node &b) { return a.size == b.size ? a.price > b.price : a.size < b.size; };
priority_queue<Node, vector<Node>, decltype(cmp)> priorityQueue(cmp);
输出结果依旧不变。
另外,由于priority_queue中的Compare模板已经确定,是一个两个参数输入,返回bool值的判断式,因此使用:
priority_queue<Node, vector<Node>, function<bool(const Node&, const Node&)>> priorityQueue(cmp);
已经可以正常运行。
需要注意的是:
priorityQueue(cmp);
。function
时需要包含头文件
,并且函数的输入参数必须和lambda表达式的输入参数类型相同。使用函数指针与3. 使用lambda表达式类似,都是在priority_queue<.,.,Cmp>中定义Compare的类型同时在priorityQueue(cmp)的中输入具体的对象作为参数,不过 这里使用的是函数和函数的指针(地址)而不是lambda表达式对象。
具体代码如下:
bool cmpFun(const Node &a, const Node &b) {
return a.size == b.size ? a.price > b.price : a.size < b.size;
}
bool (*p)(const Node &, const Node &) = cmpFun;
priority_queue<Node, vector<Node>, decltype(*p)> priorityQueue(*p);
或者:
priority_queue<Node, vector<Node>, decltype(*cmpFun)> priorityQueue(*cmpFun);
priority_queue<Node, vector<Node>, decltype(cmpFun)*> priorityQueue(cmpFun);
类似的,decltype()
也可以使用function
代替。
[1]. std::priority_queue
[2]. c++优先级队列priority_queue compare成员参数分析
[3]. C++ lambda表达式
[4]. C++ std::优先级队列priority_queue
function<>
的错误代码。function作为一个模板,两端应该为<>
,而不是()
。正确代码如下:priority_queue<Node, vector<Node>, function<bool(const Node&, const Node&)>> priorityQueue(cmp);