zoukankan      html  css  js  c++  java
  • 优先队列 讲解及模板

    定义

    优先队列(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
    ",top());
    		else pop();
    	}
    	return 0;
    } 
    

    参考来源

    百度百科

    AC_Gibson的专栏

  • 相关阅读:
    修改默认runlevel
    shell数学运算
    Ubuntu碎碎念
    编译Linux-2.6.23内核中遇见的错误
    CentOS设置静态IP
    多线程--对象锁和类锁
    [Unity移动端]Touch类
    [Lua]string与中文
    MQTT 5.0 新特性(四)Clean Start 与 Session Expiry Interval
    EMQ 9 月 新发 | EMQ X Enterprise 3.4.0 功能概览
  • 原文地址:https://www.cnblogs.com/XYZinc/p/7356442.html
Copyright © 2011-2022 走看看