一、优先队列
优先队列是一种特殊的队列,除了具有队列的性质(先进先出,队列头出,队列尾入),还具有一个及其重要的性质:实现快速得到队列中优先级最高的元素。 使得优先队列有一定的顺序特点,例如 从大到小 排列 和 从小到大 排列。
例:当优先队列为从大到小排列时,队列元素的头部始终保持数值最大,并且可以通过队尾插入数据,队首移出数据等操作,始终保持队列首端元素数值最大。
上述过程,或者说优先队列的本质,其实就是堆的操作,包含了堆的插入,移出操作,从大到小排列,本质就是一个大根堆,同理,从小到大排列本质就是一个小根堆。
二、堆实现优先队列
1. 访问队首元素(得到、弹出队首)
①访问队首元素:当堆为大根堆时(优先队列从大到小排列时),仅通过 a[1] 即可得出队首元素。
②弹出队首元素,再使其保持从大到小排列:
将队首元素输出,再将队尾元素移至队首,从队首开始实现堆的向下操作,即可保持性质。
void headdown(int x) //大根堆
{
while(1)
{
if(x>n) return ;
int child1=x*2;
int child2=child1+1;
int maxn=child1;
if(child1>n) return ;
if(child2>n)
{
if(a[maxn]>a[x])
{
swap(a[maxn],a[x]);
x=maxn;
}
else return ;
}
else
{
if(a[child1]<a[child2]) maxn=child2;
if(a[maxn]>a[x])
{
swap(a[maxn],a[x]);
x=maxn;
}
else return ;
}
}
}
-----------------------------------
printf("%d ",a[1]);
a[1]=a[n];n--;
headdown(1);
2。在优先队列中插入元素
只需要在队尾中插入该元素,再通过向上操作保持优先队列的性质。
void heapup(int x) //向上操作
{
int parent=x/2;
while(1)
{
if(a[x]>a[parent])
{
swap(a[x],a[parent]);
x=parent;
parent=x/2;
}
else return ;
}
}
3.判断队列是否为空,队列中元素个数。
都可以通过一个动态变量 n ,反应队列(堆)中的元素个数
三、STL实现优先队列
在C++中,优先队列可以通过库函数实现,和队列(queue)一样,需要用到头文件 #include<queue> , 这里先讲述普通队列的操作。
1.队列(queue)的基本操作
① 队列的定义初始化
queue<int> q; // 仅含一个参数
std::queue<int> q; // 初始化一个空队列
② 判断队列是否为空
if(q.empty()==true)
{
printf("empty");
}
else printf("No empty");
③ 获得元素个数
int n=q.size();
④返回、弹出队首元素
int x=q.front(); // 获得队首元素
q.pop(); // 弹出队首元素 出队
⑤ 入队操作
q.push(x);
2.优先队列的STL操作
①优先队列的定义
priority_queue<int>q; // 默认大根堆从小到大排
// 等同于 priority_queue<int, vector<int>, less<int> > q;
// 小根堆
// 可以将大根堆的元素取负,这样从大到小排列,即为原来元素的从小到大排列
// priority_queue<int, vector<int>, greater<int> > q;
当队列中含有多个参数时,优先队列通常会先比较第一个元素,当第一个相等时比较第二个
priority_queue< pair<int,int> > q;
int x1=q.top().first;
int x2=q.top().second;
②取出队首元素(top)
int x=q.top();
③入队,出队,判空,查询元素个数
和普通队列一样
q.push(x);
q.pop();
bool x=q.empty();
int n=q.size();
四、优先队列的说明
由于优先队列的本质是堆,所以优先队列内部操作的时间则是堆进行操作的时间,堆进行向上操作、向下操作的时间复杂度为,即优先队列的时间复杂度也为 。
STL中的队列和优先队列通常使得代码更简单,但是仍然需要知道队列与优先队列内部操作的过程(本质)。