Priority Queue
优先队列和一般的队列(queue)不同之处在于,优先队列里的元素具有权值,在出队列时总是权值最大的元素出列,本质是一个heap。
C++ Define
template <class Type, class Container= vector <Type>, class Compare= less <typename Container ::value_type>>
class priority_queue
Parameters
Parameter | description | default |
---|---|---|
Type | 队列里元素的数据类型 | |
Container | 实现队列的底层容器 | vector |
Compare | 两个元素值大小排序方式 | less |
常用的Member Functions
function | Description | Return |
---|---|---|
empty | 检查队列是否为空 | bool |
pop | 队顶元素出列 | None |
push | 基于operator将元素压入队列 | None |
size | 返回队列元素个数 | unsigned int |
top | 返回队顶元素指针 | reference |
Requirements
#include<queue>
using namespace std;
Simple Test
empty() and push()
#include<queue>
#include<iostream>
using namespace std;
int main(){
priority_queue <int> q;
if(q.empty())
cout << "the priority_queue is empty." << endl;
q.push(20);
if(!q.empty())
cout << "the priority_queue is not empty." << endl;
return 0;
}
the priority_queue is empty.
the priority_queue is not empty.
size()
#include<queue>
#include<iostream>
using namespace std;
int main(){
priority_queue <int> q;
cout << "q.size is " << q.size() <<endl;
q.push(20);
q.push(30);
cout << "q.size is " << q.size() <<endl;
return 0;
}
q.size is 0
q.size is 2
pop() and top()
#include<queue>
#include<iostream>
using namespace std;
int main(){
priority_queue <int> q;
q.push(20);
q.push(30);
q.push(19);
cout << "q.size is " << q.size() << endl;
cout << "Queue q's current top is " << q.top() << endl;
q.pop();
cout << "Queue q pops the top element." << endl;
cout << "Queue q's current top is " << q.top() << endl;
cout << "q.size is " << q.size() << endl;
return 0;
}
q.size is 3
Queue q's current top is 30
Queue q pops the top element.
Queue q's current top is 20
q.size is 2
Advanced
元素排序
默认情况下,优先队列内部是一个大根堆,元素从大到小从队首排至队尾。
#include<queue>
#include<iostream>
using namespace std;
int main(){
priority_queue <int> q; //相当于 priority_queue < int, vector<int>, less<int> > q;
q.push(20);
q.push(30);
q.push(7);
q.push(5);
q.push(12);
q.push(0);
q.push(32);
cout << "output order is :";
while( !q.empty() ){
cout << q.top() << " ";
q.pop();
}
return 0;
}
output order is :32 30 20 12 7 5 0
可以将队列声明参数Compare
对应的less
改成greater
,此时内部大根堆变成小根堆,元素从小到大排列
output order is :0 5 7 12 20 30 32
运算符重载
在实际使用中,我们往往需要对结构体数组/类按照某一个成员的值进行排序,比如想对学生所有科目中的语文成绩进行排序,那么就需要重载比较操作符函数,即参数Compare
所指向的函数。
compare
可以选择greater
或者less
,C++ 11定义两者分别为:
less
template <class T> struct less {
bool operator() (const T& x, const T& y) const {return x < y;}
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
};
greater
template <class T> struct greater {
bool operator() (const T& x, const T& y) const {return x > y;}
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
};
一般而言,排序时greater
对应从大到小顺序,less
对应从小到大顺序。但是在优先级队列里,less对应的是从大到小出队列,greater对应从小到大出队列,在前面示例的简单元素排序中可以看到刚好相反,这么实现的具体原因暂不探究。
在自定义结构体优先级时,可以使用以下两种方式:
//方式一:以成员函数的形式
#include<queue>
#include<iostream>
using namespace std;
struct Student{
//简单起见,只定义两个成绩变量
int num;
int math;
Student(int n, int m){
num = n;
math = m;
}
bool operator< (const Student &s) const { //这里const不能漏,会报错(codeblocks)
return math < s.math;
}
};
int main(){
priority_queue < Student, vector<Student>, less<Student> > q;
q.push(Student(7,80));
q.push(Student(6,30));
q.push(Student(3,45));
q.push(Student(2,100));
q.push(Student(5,76));
q.push(Student(10,34));
cout << "数学成绩排序为:" ;
while( !q.empty() ){
cout<< q.top().math << " ";
q.pop();
}
return 0;
}
//方式二:以结构体形式
#include<queue>
#include<iostream>
using namespace std;
struct Student{
//简单起见,只定义两个成绩变量
int num;
int math;
Student(int n, int m){
num = n;
math = m;
}
};
struct cmp{
bool operator ()(const Student s1, const Student s2){
return s1.math < s2.math;
}
};
int main(){
priority_queue < Student, vector<Student>, cmp > q; //这里要用结构体cmp替换原来的less/greater
q.push(Student(7,80));
q.push(Student(6,30));
q.push(Student(3,45));
q.push(Student(2,100));
q.push(Student(5,76));
q.push(Student(10,34));
cout << "数学成绩排序为:" ;
while( !q.empty() ){
cout<< q.top().math << " ";
q.pop();
}
return 0;
}
输出结果均为:
数学成绩排序为:100 80 76 45 34 30
注意
针对方式一,如果在声明中compare
选择greater
,则在结构体中重载函数名必须对应为operator >
,即重载运算符>
;同理,less
对应operator <
,即重载运算符<
, 即:
//greater ----- operator>
priority_queue < Student, vector<Student>, greater<Student> > q;
bool operator> (const Student &s) const {}
//less ----- operator<
priority_queue < Student, vector<Student>, less<Student> > q;
bool operator< (const Student &s) const {}
针对方式二,重载运算符必须是()
, 即:
bool operator ()(const Student s1, const Student s2) {}
否则会报错。
但是,最终排序结果只与return
语句中的运算符有关,即:
//如果你想让元素从大到小出列,则return中运算符应为'<'
return math < s.math;
//如果你想让元素从小到大出列,则return中运算符应为'>'
return math > s.math
小结
以上内容浅入浅出,只是为了OJ刷题需要,没有追根溯源。如有错误,欢迎指正!