STL | priority_queue(优先队列)基本用法
写在前面:
priority_queue ,又称优先队列 ,是一个容器——允许在时间复杂度下插入 数据、在
时间复杂度下取得容器内最大(最小)值 。
其本质就是一个堆 ,只是比我们自己手写堆 多了一些优化罢了(没有优化也就不会纳入STL中啦)。
使用STL的priority_queue需要包含头文件queue ,即
#include<queue>
优先队列:
一. 定义
优先队列priority_queue的定义如下:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
Parameter | Description | Default |
---|---|---|
T | The type of object stored in the priority queue. | |
Container | The type of the underlying container used to implement the priority queue. | vector<T> |
Compare | The comparison function used to determine whether one element is smaller than another element.If Compare(x,y) is true, then x is smaller than y.The element returned by Q.top() is the largest element in the priority queue.That is, it has the property that, for every other element x in the priority queue, Compare(Q.top(), x) is false. | less<T> |
参数 | 描述 | 默认值 |
---|---|---|
数据类型 T | 优先队列中存放的数据类型 | |
容器 | 用于实现优先队列(潜在)的容器类型 | vector<T> |
比较函数(优先级) | 用于确定一个元素是否小于另一个元素的比较函数。如果Compare(x, y)是正确的,那么x小于y,优先队列Q.top()返回的就是最大的元素。此时,优先队列队头元素Q.top()与优先队列Q中所有其他元素x进行比较,即Compare(Q.top (), x) 是错误的 | less<T> |
Container:必须是用数组实现的容器,比如 vector, deque,但不能用 list。STL里面默认用的是 vector。
Compare:比较方式默认用使用less<T>,operator <(小于号)。
所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。
二. 默认的优先队列——大顶堆
priority_queue<int>que;
等价于
priority_queue<int,vector<int>,less<int> >que;
注意需要添加头文件vector,即#include<vector>
可以在下面的测试程序中,动手尝试一下
#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<ctime>
#include<cstdlib>
using namespace std;
priority_queue<int>que;// 默认的优先队列
//priority_queue<int,vector<int>,less<int> >que;
int test[1010];
int main()
{
// 使用一个简易的随机数(不能超过值RAND_MAX)进行测试
srand((int)time(0));
for(int i=0;i<100;i++)test[i]=rand(),que.push(test[i]);
// 入队列之前
cout<<"Before:\n";
for(int i=0;i<100;i++)cout<<test[i]<<" ";
cout<<endl;
// 入队列之后
cout<<"After:\n";
while(!que.empty())
{
cout<<que.top()<<" ";
que.pop();
}
}

三. 更改比较函数——仿函数greater<T>
默认的优先队列是大顶堆,那么,如果我们想要变为小顶堆 ,可以使用STL中的仿函数
greater<T>(默认的使用的是less<T>)。
对上面的程序中,优先队列的定义进行如下修改,
priority_queue<int,vector<int>,greater<int> >que;
重新运行程序,得到下面结果(可以看出此时优先队列相当于一个小顶堆 )。

四. 自定义类型——大顶堆
STL中的仿函数less<T>和greater<T>的使用范围仅限于基本类型,当优先队列需要保存我们自定义的数据类型时,我们需要重载小于号(operator <)或者写仿函数,这两种方式定义的优先队列稍有不同。
① 重载小于运算符 <:
// 重载 < 运算符,实现大顶堆
//(堆顶元素:先根据x,选择x最大的元素;若两个元素的x值相同,再根据y,选择两者中y较大的元素)
bool operator<(My_Type a,My_Type b)
{
// 定义排序规则
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
// 定义优先队列
priority_queue<My_Type>que;
② 仿函数:
// 仿函数,实现大顶堆
struct cmp
{
// 定义排序规则
bool operator() (My_Type a,My_Type b )
{
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
};
// 定义优先队列
priority_queue<My_Type,vector<My_Type>,cmp>que;
③ 完整代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstdlib>
#include<ctime>
using namespace std;
// 自定义一种结构体类型
typedef struct
{
int x;
int y;
}My_Type;
// 仿函数,实现大顶堆
struct cmp
{
// 定义排序规则
bool operator() (My_Type a,My_Type b )
{
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
};
// 重载 < 运算符,实现大顶堆
//(堆顶元素:先根据x,选择x最大的元素;若两个元素的x值相同,再根据y,选择两者中y较大的元素)
bool operator<(My_Type a,My_Type b)
{
// 定义排序规则
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
vector<My_Type>vec;
//priority_queue<My_Type,vector<My_Type>,cmp>que;
priority_queue<My_Type>que;
int main()
{
My_Type temp;
srand((int)time(NULL));
for(int i=0;i<10;i++)
{
temp.x=rand();
temp.y=rand();
vec.push_back(temp);
que.push(temp);
}
cout<<"Before:\n";
for(int i=0;i<10;i++)
{
cout<<vec[i].x<<" "<<vec[i].y<<endl;
}
cout<<"\nAfter:\n";
while(!que.empty())
{
temp=que.top();
cout<<temp.x<<" "<<temp.y<<endl;
que.pop();
}
}

五. 自定义类型——小顶堆
若要实现一个小顶堆,与上面的程序差不多,仅仅需要更改一下排序规则即可:
① 重载小于运算符 <:
// 重载 < 运算符,实现小顶堆
bool operator<(My_Type a,My_Type b)
{
// 定义排序规则
if(a.x==b.x) return a.y>b.y;
return a.x>b.x;
}
② 仿函数:
// 仿函数,实现小顶堆
struct cmp
{
// 定义排序规则
bool operator() (My_Type a,My_Type b )
{
if(a.x==b.x)return a.y>b.y;
return a.x>b.x;
}
};
六. 优先队列的用途:
一开始我们便提到了,优先对了是一个容器——允许在时间复杂度下插入 数据、在
时间复杂度下取得容器内最大(最小)值 。
正是由于优先队列这样的特征(时间复杂度低),使得在一些算法中可以使用优先队列来进行优化:
-
哈夫曼树 & 哈夫曼编码
-
最小生成树的Prim算法
(PS:未完待续,遇到了再做补充)
七. 其他一些常见的函数:
函数 | 功能 |
---|---|
empty() | 如果优先队列为空,则返回真 |
top() | 返回优先队列中有最高优先级的元素 |
pop() | 删除第一个元素 |
push() | 插入一个元素 |
size() | 返回优先队列中拥有的元素的个数 |
写在最后:
参考资料:
优先队列,虽然叫队列,但是其本质却是堆(一种特殊的二叉树)。
看待一个人,以貌取人往往是不够的,更多的是看他生活的点滴,从生活的蛛丝马迹中了解一个人。