zoukankan      html  css  js  c++  java
  • C++STL容器priority_queue(优先队列)简述

    优先队列的默认实现

    STL容器中提供了 priority_queue(优先队列) 来实现类似堆的功能。

    为了方便说明其用法,接下来的讲述中直接将 priority_queue 看做堆来讲述。

    和用于排序的 sort 函数一样,priority_queue 默认的比较规则都是 <(小于号)。

    sort 默认会根据小于号将元素从小到大排序;

    priority_queue 中的元素默认是根据小于号的比较规则将最大的作为其堆顶元素。这个跟 sort 的思路有点不一样, priority_queue 是 “我比你小,则我把你推到顶上去” 的意思。

    就是说,默认情况下,priority_queue 中的元素总是最大的那个作为堆顶元素。

    所以默认的 priority_queue 是一个大根堆

    定义一个 priority_queue 的一般格式为:

    priority_queue<类型名> 容器名;
    

    其最常用的成员方法有:

    • push(a):往堆中推入一个元素 a
    • top():获得堆顶元素;
    • pop():弹出堆顶元素;
    • empty():判断容器是否为空(为空返回true);
    • size():返回目前该容器中包含元素的个数。

    示例程序:

    #include <bits/stdc++.h>
    using namespace std;
    priority_queue<int> que;
    int main() {
        for (int i = 3; i <= 6; i ++)
            que.push(i);
        que.push(1);
        que.push(8);
        cout << "size = " << que.size() << endl;
        while (!que.empty()) {
            cout << que.top() << ",";
            que.pop();
        }
        return 0;
    }
    

    输出结果:

    size = 6
    8,6,5,4,3,1,
    

    使用优先队列来实现小根堆

    默认的比较规则是 <(小于号),但是我们也可以在定义 priority_queue 的时候讲规则进行修改。比如下面的代码段就定义了一个大根堆:

    priority_queue<int, vector<int>, greater<int> > que;
    

    其中,priority_queue 后的尖括号中:

    • int 表示数据类型;
    • vector<int> 表示数据的存储方式,在这里是使用 vector 存储(据说这样写上会快一些,不过我这里主要还是为了占一个位置,方便写第三个参数);
    • greater<int> 表示比较规则,这个 greater<int> 对应的比较规则就是 >(大于号),即 “我比你大,我把你推到顶上去”。

    需要注意的是,如果 priority_queue 存储的是别的类型的数据,则对应的数据类型都得进行相应的修改,如下下面的代码段定义了一个存储 double 类型数据的小根堆:

    priority_queue<double, vector<double>, greater<double> > que;
    

    示例程序(优先队列实现小根堆):

    #include <bits/stdc++.h>
    using namespace std;
    priority_queue<int, vector<int>, greater<int> > que;
    int main() {
        for (int i = 3; i <= 6; i ++)
            que.push(i);
        que.push(1);
        que.push(8);
        cout << "size = " << que.size() << endl;
        while (!que.empty()) {
            cout << que.top() << ",";
            que.pop();
        }
        return 0;
    }
    

    输出结果:

    size = 6
    1,3,4,5,6,8,
    

    优先队列+结构体

    对于结构体类型的变量来说,默认没有 <(小于号),这种情况下直接使用该结构体类型的 priority_queue 显然是不行的(会报错)。

    所以可以考虑为新定义的结构体类型定义一个 < 的功能,这种操作被称作 重载运算符

    比如,下面的程序中,我将定义一个名为 Node 的结构体并为其重载 < 运算符(因为 priority_queue 默认看的就是 < 运算符),并实现一个 Node 类型的优先队列。示例程序:

    #include <bits/stdc++.h>
    using namespace std;
    struct Node {
        int x, y;
        // 重载小于号运算符
        bool operator < (const Node b) const {
            return x < b.x || x == b.x && y < b.y;
        }
    };
    priority_queue<Node> que;   // 使用Node默认的比较规则
    
    int main() {
        que.push({3, 5});
        que.push({2, 4});
        que.push({1, 3});
        que.push({4, 2});
        que.push({3, 3});
        while (!que.empty()) {
            Node u = que.top();
            que.pop();
            cout << "(" << u.x << " , " << u.y << ")" << endl;
        }
        return 0;
    }
    

    程序输出结果:

    (4 , 2)
    (3 , 5)
    (3 , 3)
    (2 , 4)
    (1 , 3)
    

    自定义优先队列的比较规则

    有的时候,有的数据类型可能已经封装好了 < 运算符,或者其 < 运算符还有别的用处,这种情况下我们不能再为其重载 < 运算符,那么这个时候怎么办呢?

    回顾一下,在使用 sort 函数的时候,我们定义过比较函数(一般取名为 cmp,国际惯例)。

    然后在 sort 的时候讲 cmp 函数作为 sort 函数的第三个参数。

    在 priority_queue 中也可以使用类型的功能,只不过 priority_queue 使用的是 比较结构体

    我们可以定义一个名为 Cmp 的结构体并重载其 () 运算符,然后将其作为 priority_queue 定义时尖括号中的第三个参数。比如,下面的程序为 Node 类型匹配了一个对应的 Cmp 类型,并使用 Cmp 的比较规则实现了一个优先队列。

    #include <bits/stdc++.h>
    using namespace std;
    struct Node {
        int x, y;
    };
    struct Cmp {    // 比较结构体
        bool operator () (Node &a, Node &b) {
            return a.x < b.x || a.x == b.x && a.y < b.y;
        }
    };
    priority_queue<Node, vector<Node>, Cmp> que;   // 定义que时使用Cmp作为比较规则
    int main() {
        que.push({3, 5});
        que.push({2, 4});
        que.push({1, 3});
        que.push({4, 2});
        que.push({3, 3});
        while (!que.empty()) {
            Node u = que.top();
            que.pop();
            cout << "(" << u.x << " , " << u.y << ")" << endl;
        }
        return 0;
    }
    

    输出结果:

    (4 , 2)
    (3 , 5)
    (3 , 3)
    (2 , 4)
    (1 , 3)
    
  • 相关阅读:
    在Xcode 查看预处理及预编译阶段“宏”Marcos
    复用的基础
    抖音品质建设
    Mach-O 文件格式
    isaclass object_getClass
    组件化接口依赖一致性问题
    objectClasses and metaclasses
    __attribute__详解及应用
    深入静态库 & 动态库--[iOS] 组件二进制化 & 库的各种小知识
    iOS应用的启动流程和优化详解
  • 原文地址:https://www.cnblogs.com/quanjun/p/15705322.html
Copyright © 2011-2022 走看看