• 算法笔记--标准模板库STL--priority_queue


    priority_queue 的常见用法

    priority_queue又称为优先队列,其底层使用堆实现

    在优先队列中,队首元素一定要是当前队列中优先级最高的那个

    在任何时候往优先队列里面加入(push)元素,而优先队列底层的数据结构堆(heap)会随时调整结构,使得每次的队首元素都是优先级最大的

    头文件

    #include<queue>
    using namespace std;
    

    priority_queue的定义

    priority_queue<typename> name;
    

    priority_queue容器内元素的访问

    不同于普通队列,优先队列没有front()back()函数,而是能通过top()来访问队首元素(也可以称为堆顶元素),也就是优先级最高的元素

    #include<stdio.h>
    #include<queue>
    using namespace std;
    
    int main(){
        priority_queue<int> q;
        q.push(3);
        q.push(4);
        q.push(1);
        printf("%d", q.top());	// 结果为: 4
        return 0;
    }
    

    priority_queue常用函数

    push( )

    push( ) 将令x入队,时间复杂度为O(logN),其中N为当前优先队列的元素个数

    top( )

    top( ) 可以(访问)获得队首元素,时间复杂度为O(1)

    pop( )

    pop( ) 令队首元素出队,时间复杂度为O(logN)

    #include<stdio.h>
    #include<queue>
    using namespace std;
    
    int main(){
        priority_queue<int> q;
        q.push(3);
        q.push(4);
        q.push(1);
        printf("%d
    ", q.top());	// 4
        q.pop();
        printf("%d
    ", q.top());	// 3
        return 0;
    }
    

    empty( )

    empty( ) 检测队列是否为空,空返回true,非空返回false,时间复杂度为O(1)

    #include<stdio.h>
    #include<queue>
    using namespace std;
    
    int main(){
        priority_queue<int> q;
        q.push(3);
        q.push(4);
        q.push(1);
    
        q.empty() ? printf("Empty
    ") : printf("NO Empty
    ");
    
        for(int i = 1; i <= 3; i++){
            q.pop();
        }
    
        q.empty() ? printf("Empty
    ") : printf("NO Empty
    ");
    
        return 0;
    }
    
    NO Empty
    Empty
    

    size( )

    size( ) 返回优先队列内元素的个数,时间复杂度为O(1)

    #include<stdio.h>
    #include<queue>
    using namespace std;
    
    int main(){
        priority_queue<int> q;
        q.push(3);
        q.push(4);
        q.push(1);
        printf("%d", q.size());	// 3
        return 0;
    }
    

    priority_queue内元素优先级的设置

    基本数据类型的优先级设置

    对于基本数据类型,一般数字大的优先级高,因此队首元素就是优先队列内元素最大的那个(如果char型,则是字典序最大的)

    对于基本数据类型来说,下面两种优先队列的定义是等价的:

    priority_queue<int> q;
    priority_queue<int, vector<int>, less<int>> q;
    // vector<int> 是用来承载底层数据结构堆(heap)的容器
    // less<int> 表示数字大的优先级大,great<int> 表示数字小的优先级大
    

    如,想让优先队列总是把最小的元素放在队首,

    priority_queue<int, vector<int>, greater<int>> q;
    
    #include<stdio.h>
    #include<queue>
    using namespace std;
    
    int main(){
        priority_queue<int, vector<int>, greater<int>> q;
        q.push(3);
        q.push(4);
        q.push(1);
        printf("%d", q.top()); // 1
        return 0;
    }
    

    结构体的优先级设置

    如水果的结构体如下:

    struct fruit{
        string name;	// 水果名称
        int price;		// 水果价格
    }
    

    现在希望按照水果的价格高的为优先级高,就需要重载overload小于号<

    重载:对已有运算符进行重新定义,也就是说,可以改变小于号的功能

    struct fruit{
        string name;
        int price;
        friend bool operator < (fruit f1, fruit 2){
            return f1.price < f2.frice;
        }
    }
    

    此时就可以直接定义fruit类型的优先队列,其内部就是以价格高的水果为优先级高,

    priority_queue<fruit> q;
    

    如果要以价格低的水果优先级高,那么只需要把return中的小于号改为大于号

    #include<iostream>
    #include<queue>
    #include<string>
    using namespace std;
    
    struct fruit{
        string name;
        int price;
        friend bool operator < (fruit f1, fruit f2){
            return f1.price > f2.price;
        }
    }f1, f2, f3;
    
    int main(){
        priority_queue<fruit> q;
        f1.name = "桃子";
        f2.name = "栗子";
        f3.name = "苹果";
        f1.price = 4;
        f2.price = 2;
        f3.price = 7;
        q.push(f1);
        q.push(f2);
        q.push(f3);
        cout << q.top().name << "  " << q.top().price << endl;
        return 0;
    }
    
    栗子 2
    

    优先队列中对小于号重载的函数和sort()中的cmp函数是相反的

    当然,重载函数也可以写在结构体外:

    #include<iostream>
    #include<queue>
    #include<string>
    using namespace std;
    
    struct fruit{
        string name;
        int price;
    }f1, f2, f3;
    
    struct cmp{
       bool operator () (fruit f1, fruit f2){
            return f1.price > f2.price;
       }
    };
    
    int main(){
        priority_queue<fruit, vector<fruit>, cmp> q;
        f1.name = "桃子";
        f2.name = "栗子";
        f3.name = "苹果";
        f1.price = 4;
        f2.price = 2;
        f3.price = 7;
        q.push(f1);
        q.push(f2);
        q.push(f3);
        cout << q.top().name << "  " << q.top().price << endl;
        return 0;
    }
    

    所以,即便是基本数据类型或者其他STL容器,也可以通过同样的方式定义优先级

    如果结构体内的数据量较为庞大(如出现了字符串或者数组),建议使用引用来提高效率,此时比较类的参数中需要加上const&

    friend bool operator < (const fruit &f1, const fruit &f2){
        return f1.price > f2.price;
    }
    
    bool operator () (const fruit &f1, const fruit &f2){
        return f1.price > f2.price;
    }
    

    priority_queue的常见用途

    • 贪心问题
    • Dijkstra算法

    注意:使用top()之前必须先用empty()判断队列是否为空

    Write by Gqq

  • 相关阅读:
    [BZOJ3829][Poi2014]FarmCraft 贪心
    【BZOJ 3144】 [Hnoi2013]切糕 真·最小割
    【BZOJ1458】士兵占领 最大流的模板题
    【COGS 14】 [网络流24题] 搭配飞行员 网络流板子题
    【BZOJ 4832】 [Lydsy2017年4月月赛] 抵制克苏恩 期望概率dp
    【BZOJ4325】NOIP2015 斗地主 搜索+贪心
    【BZOJ 1409】 Password 数论(扩展欧拉+矩阵快速幂+快速幂)
    【NOIP模拟赛】天神下凡 动态开点线段树
    【NOIP模拟赛】藏宝图 最小生成树
    【NOIP模拟赛】黑红树 期望概率dp
  • 原文地址:https://www.cnblogs.com/zgqcn/p/12588342.html
Copyright © 2020-2023  润新知