详细说明优先级队列的使用方法

简介

优先级队列是一种常见的数据结构,在《STL源码剖析》中给出的定义是:priorty_queue是以个带权值观念的queue,它允许加入新元素,移除旧元素,审视元素值等功能。由于这是一个queue,所以只允许在底端加入元素,并从顶端取出元素。
但是优先级队列中的元素并非依照被推入队列的顺序排列。而是自动依照元素的权值排列。权值最高者排在最前面。
缺省的情况下维护的是一个大堆,即权值以从高到低排列。

优先级队列

优先级队列的使用

因为优先级队列的内部是用堆来维护,所以很多时候我们要使用堆的情况下会选择用优先级队列来代替

这个地方给出官方文档中优先级队列的用法。
https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=ZH-CN&k=k(priority_queue);k(DevLang-C%2B%2B);k(TargetOS-Windows)&rd=true

下面我们来说以下常用的几种

1.

int main()
{
    priority_queue<int> p1;//往队列里直接存入整型
    p1.push(5);
    p1.push(4);
    p1.push(6);
    p1.push(3);
    p1.push(1);
    for (int i = 0; !p1.empty(); ++i)
    {
        cout << p1.top() << " ";
        p1.pop();
    }
    return 0;
}

这种用法是最常用的一种,优先级判断默认使用<操作符,输出按权值从高到低顺序。输出如图。
优先级队列使用1

2.

如果我们想要按照权值从低到高的顺序输出的话就要使用这种方式。

priority_queue<int, vector<int>, greater<int> > qi

第一个参数为元素的类型,第二个参数为容器类型,第三个参数为比较函数(默认为less),上面的为从小到大的优先级队列,如果将greater改为less或者删去第三个参数,即为权值从大到小排列。如图。注意greater包含在头文件functional内。
优先级队列的使用2

3.

有时候我们想要往队列里存储结构体,那么为了实现和内置类型一样的优先级比较,我们就必须在结构体中实现对“<”的重载。因为优先级队列在内部实现调整的时候会去找“<”操作符,如果找不到就会报错。如下所示。

struct Node
{
    char val;
    int priority;
    Node(char c,int priority)
        :val(c)
        ,priority(priority)
    {}

    friend bool operator < (Node n1,Node n2)
    {
        return n1.priority < n2.priority;//<为权值大到小排列
        //return n1.priority > n2.priority;//>为权值小到大排列
    }
};

int main()
{
    Node n1('a',5);
    Node n2('b',4);
    Node n3('c',6);
    Node n4('d',3);
    Node n5('e',1);

    priority_queue<Node> p1;
    p1.push(n1);
    p1.push(n2);
    p1.push(n3);
    p1.push(n4);
    p1.push(n5);

    for (int i = 0; !p1.empty(); ++i)
    {
        cout << p1.top().val << " ";
        p1.pop();
    }
    return 0;
}

运行结果如图
优先级队列使用5

注意

在网上很多博客在讲解如何使用优先级队列的时候都采用了如下的方式

priority_queue<Node, vector<Node>, greater<Node> > qi

即调用了库中给出的greater函数,但是我尝试使用之后发现这种方式不能在结构体中重载“<”,而应该重载“>”操作符。因为greater函数和less函数在内部实现的时候使用了不同的操作符。
greater
less
greater中使用了“>”,所以在使用greater的时候应该重载“>”,
less中使用了“<”,所以在使用less或者在缺省的情况下应该重载“<”。
而网上大部分博客中不分情况重载“<”是不对的。

4.

但是在函数重载的规定中又指出,重载的操作对象只能是类类型或枚举类型,那么如果优先级队列中存放的是指针类型的对象就只能使用另一种方法,使用仿函数,传递一个优先级比较的算法到优先级队列中。

priority_queue<Node*,vector<Node*>,Comapre> qi

这里的Node*是指队列中存储的是指向Node的结构体的指针,此时就不能使用标准库中用<操作符来实现优先级排序的这种方式了。这里我们实现一个类使用仿函数传入一个比较的算法,就可以实现优先级的判断了。
如下例

struct Node
{
    int priotiry;
    char val;
    Node(char ch, int pri)
        :val(ch)
        ,priotiry(pri)
    {}

    char getval()
    {
        return val;
    }
};

struct cmp
{
    bool operator()(const Node *n1, const Node *n2) const
    {
        return n1->priotiry < n2->priotiry;
    }
};


int main()
{
    Node *n1 = new Node('a',5);
    Node *n2 = new Node('b',4);
    Node *n3 = new Node('c',6);
    Node *n4 = new Node('d',3);
    Node *n5 = new Node('e',1);

    priority_queue<Node*,vector<Node*>,cmp> p1;
    p1.push(n1);
    p1.push(n2);
    p1.push(n3);
    p1.push(n4);
    p1.push(n5);

    for (int i = 0; !p1.empty(); ++i)
    {
        cout << p1.top()->getval() << " ";
        p1.pop();
    }
    return 0;
}

输出结果与第三种情况相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值