优先队列 讲解及模板

定义

优先队列(priority queue)
普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。

通俗来讲,就是按一定优先顺序弹出元素的队列

时间复杂度为O(logn)

使用

  • 优先队列在头文件#include < queue >中

  • 声明格式

    priority_queue < int > q;//定义一个整形优先队列(默认为大根堆)

    priority_queue< int,vector < int >, greater< int > >q;//小根堆

    priority_queue< int,vector < int >,less< int > >q;//大根堆

  • 基本操作

    q.push( );//插入元素

    q.pop( );//删除堆顶元素

    q.top( );//弹出堆顶元素

    q.empty( );//判断队列是否为空

    q.size( );//返回队列中元素个数

优先级

在大根堆中,认为数值大的优先级高;小根堆中,认为数值小的优先级高

但有些时候,我们需要自行定义队列元素的优先级,可以使用结构体设置优先级

//方法1

struct cmp1()
{
    bool operator() (int &a,int &b)
    {
        return a>b;//较小值优先级高
    }
}

srtuct cmp2()
{
    bool operator() (int &a,int &b)
    {
        return a<b;//较大值优先级高
    }
}

priority_queue<int,vector<int>,cmp1>q1;//小根堆

priority_queue<int,vector<int>,cmp2>q2;//大根堆 

//方法2

struct node1
{
    int x;
    bool operator < (const node1 &a) const     
    {      
       return x>a.x;//较小值优先级高   
    }      
}

struct node2
{
    int x;
    bool operator < (const node2 &a) const
    {
        return x<a.x;//较大值优先级高
    }
}

priority_queue<node1>q1;//小根堆

priority_queue<node2>q2;//大根堆

//定义结构体的优先级

struct node  
{  
    int x, y;  
    friend bool operator < (node a, node b)  
    {  
        return a.x>b.x;//结构体中,以x判定优先级  
    }  
};  

priority_queue<node>q;

手写堆

能熟练使用系统堆的同时,也应了解如何手写堆

插入操作

优先队列的插入操作与普通队列相似,将新元素插入队尾,只是在插入完成后需要对插入的元素进行“上浮”,即按优先级将其转移到适宜位置

这里以小根堆为例

void push(int x)
{
    q[++sz]=x;
    int pos=sz;
    while(pos>1&&q[pos>>1]>q[pos])//若父节点大于当前节点,交换
        swap(q[pos],q[pos>>1]),pos=pos>>1;
}

删除操作

小根堆的本质是一个二叉树,直接删除堆顶即删掉根节点,会导致左右儿子的松散,是不合适的,不妨取出队尾元素,覆盖掉堆顶,再通过上浮操作维护

void pop()
{
	int pos=1;
    q[pos]=q[sz--];
	while(true)
	{
		int lv=(pos<<1)>sz? inf:q[pos<<1];
        int rv=(pos<<1|1)>sz? inf:q[pos<<1|1];
        int v=min(lv,rv),nt=lv<rv? (pos<<1):(pos<<1|1);
        if(q[pos]>v)
        	swap(q[pos],q[nt]),pos=nt;
        else break;
	}
}

其他

int top() {return q[1];}

int size() {return sz;}

bool empty() {return sz==0? true:false;}

void clear() {sz=0;}//系统队列好像不支持清空,只能一个一个pop() ???

模板

luogu3378

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath> 
#define inf 2147483646
#define N 1000005
using namespace std; 

int q[N],sz,n;
int top() {return q[1];} 

void push(int x)
{
    q[++sz]=x;
    int pos=sz;
    while(pos>1&&q[pos>>1]>q[pos])
        swap(q[pos],q[pos>>1]),pos=pos>>1;
}

void pop()
{
	int rt=q[sz--],pos=1;
	q[pos]=rt;
	while(true)
	{
		int lv=(pos<<1)>sz? inf:q[pos<<1];
        int rv=(pos<<1|1)>sz? inf:q[pos<<1|1];
        int v=min(lv,rv),nt=lv<rv? (pos<<1):(pos<<1|1);
        if(q[pos]>v)
        	swap(q[pos],q[nt]),pos=nt;
        else break;
	}
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int opt,x;scanf("%d",&opt);
		if(opt==1) scanf("%d",&x),push(x);
		else if(opt==2) printf("%d\n",top());
		else pop();
	}
	return 0;
} 

参考来源

百度百科

AC_Gibson的专栏

posted @ 2017-08-14 10:30  XYZinc  阅读(591)  评论(0编辑  收藏  举报