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)
    
  • 相关阅读:
    XML(学习笔记)
    css样式学习笔记
    Request(对象)
    sql一些错误修改的总结
    转载(如何学习C#)
    sql server(学习笔记2 W3Cschool)
    sql sqrver(学习笔记1 W3Cschool)
    关于 flutter开发碰到的各种问题,有的已经解决有的一直没解决或者用其他方法替代
    关于 Flutter IOS build It appears that your application still contains the default signing identifier.
    关于 flutter本地化问题 The getter 'pasteButtonLabel' was called on null
  • 原文地址:https://www.cnblogs.com/quanjun/p/15705322.html
Copyright © 2011-2022 走看看