STL学习——priority_list的使用和学习

本文主要介绍优先队列,它是功能强大的队列,具备自动排序特性。文中讲解了优先队列的头文件声明、基本操作,分析了不同声明方式下的排序规则,如默认队列、结构体重载小于、less和greater优先队列。还阐述了其底层基于堆实现,最大优先队列用大堆,最小优先队列用小堆。

引入

说白了,就是一种功能强大的队列。如果不太清楚队列,可以看看我这篇博客。

它的功能强大在哪里呢?
四个字:自动排序。

优先队列的头文件声明
首先,你需要

#include<queue>
using namespace std;

这两个头文件。

其次,一个优先队列声明的基本格式是:
priority_queue<结构类型> 队列名;
比如:

priority_queue <int> i;
priority_queue <double> d;

不过,我们最为常用的是这几种:

priority_queue <*node*> q;
//node是一个结构体
//结构体里重载了‘<’小于符号
priority_queue <int,vector<int>,greater<int> > q;
//不需要#include<vector>头文件
//注意后面两个“>”不要写在一起,“>>”是右移运算符
priority_queue <int,vector<int>,less<int> >q;

我们将在下文来讲讲这几种声明方式的不同。

优先队列的基本操作,与队列的基本操作如出一辙。
以一个名为q的优先队列为例。

q.size();//返回q里元素个数
q.empty();//返回q是否为空,空则返回1,否则返回0
q.push(k);//在q的末尾插入k
q.pop();//删掉q的第一个元素
q.top();//返回q的第一个元素
q.back();//返回q的末尾元素

优先队列的特性:上文已经说过了,自动排序。
怎么个排法呢? 在这里介绍一下:

默认的优先队列(非结构体结构)
priority_queue q;

这样的优先队列是怎样的?让我们写程序验证一下。

#include<cstdio>
#include<queue>
using namespace std;
priority_queue <int> q;
int main()
{
    q.push(10),q.push(8),q.push(12),q.push(14),q.push(6);
    while(!q.empty())
        printf("%d ",q.top()),q.pop();

程序大意就是在这个优先队列里依次插入10、8、12、14、6,再输出。
结果是什么呢?
14 12 10 8 6
也就是说,它是按从大到小排序的!

默认的优先队列(结构体,重载小于)
先看看这个结构体是什么。

struct node
{
    int x,y;
    bool operator < (const node & a) const
    {
        return x<a.x;
    }
};

这个node结构体有两个成员,x和y,它的小于规则是x小者小。
再来看看验证程序:

#include<cstdio>
#include<queue>
using namespace std;
struct node
{
    int x,y;
    bool operator < (const node & a) const
    {
        return x<a.x;
    }
}k;
priority_queue <node> q;
int main()
{
    k.x=10,k.y=100; q.push(k);
    k.x=12,k.y=60; q.push(k);
    k.x=14,k.y=40; q.push(k);
    k.x=6,k.y=80; q.push(k);
    k.x=8,k.y=20; q.push(k);
    while(!q.empty())
    {
        node m=q.top(); q.pop();
        printf("(%d,%d) ",m.x,m.y);
    }
}

程序大意就是插入(10,100),(12,60),(14,40),(6,20),(8,20)这五个node。
再来看看它的输出:
(14,40) (12,60) (10,100) (8,20) (6,80)

它也是按照重载后的小于规则,从大到小排序的。

less和greater优先队列
还是以int为例,先来声明:

priority_queue <int,vector,less > p;
priority_queue <int,vector,greater > q;

话不多说,上程序和结果:

#include<cstdio>
#include<queue>
using namespace std;
priority_queue <int,vector<int>,less<int> > p;
priority_queue <int,vector<int>,greater<int> > q;
int a[5]={10,12,14,6,8};
int main()
{
    for(int i=0;i<5;i++)
        p.push(a[i]),q.push(a[i]);

    printf("less<int>:")
    while(!p.empty())
        printf("%d ",p.top()),p.pop();  

    pritntf("\ngreater<int>:")
    while(!q.empty())
        printf("%d ",q.top()),q.pop();
}

结果:

less:14 12 10 8 6
greater:6 8 10 12 14

所以,我们可以知道,less是从大到小,greater是从小到大。

作个总结,为了装13方便,在平时,建议大家写:

priority_queue<int,vector<int>,less<int> >q;
priority_queue<int,vector<int>,greater<int> >q;

平时如果用从大到小不用后面的vector,less,可能到时候要改成从小到大,你反而会搞忘怎么写greater,反而得不偿失。

底层实现

优先级队列是在堆的基础上进行的一个扩展,主要是运用大堆来实现优先级队列,让优先度高的出队列,最大优先队列可以选用大堆,最小优先队列可以选用小堆来实现。

下面以最大优先队列来讲解其原理。
最大优先队列一般包括将一个元素插入到集合S中、返回集合S中具有最大key的元素、返回并删除集合S中具有最大key的元素等。

//堆的实现代码如下 :

#include <vector>
#include <assert.h>
using namespace std;
template<class T>
struct Less
{
    bool operator()(const T& left, const T& right)
    {
        return left < right;
    }
};

template<class T>
struct Greater
{
    bool operator()(const T& left, const T& right)
    {
        return left > right;
    }
};
template<class T, class Compare = Less<T>>
class Heap
{
public:
    Heap()
    {}

    Heap(const T array[], size_t size)
    {
        _heap.reserve(size);
        for (size_t i = 0; i < size; i++)
        {
            _heap.push_back(array[i]);
        }
        for (int j = (_heap.size() - 2) / 2; j >= 0; j--)
        {
            _AdjustDown(j);
        }
    }
    void Insert(const T& data)
    {
        assert(data);
        assert(!_heap.empty());
        _heap.push_back(data);
        _Adjustup(_heap.size() - 1);
    }
    void Remove()
    {
        assert(!_heap.empty());
        swap(_heap[0], _heap[size() - 1]);
        _heap.pop_back();
        _AdjustDown(0);
    }
    void Push(const T& x)  
    {  
        //插入到尾部,再从最后一个元素开始向上调整  
            _a.push_back(x);  
            AdjustUp(_a.size()-1);  
        }  
        void Pop()
    {
        //将堆顶与最后一个元素交换,再从堆顶下滑调整  
        assert(!_a.empty());
        swap(_a[0], _a[_a.size() - 1]);
        _a.pop_back();
        if (_a.size()>1)         //如果堆中的元素大于一个,再进行调整  
        {
            AdjustDown(0, _a.size());
        }
    }
    size_t Size()const
    {
        return _heap.size();
    }

    bool Empty()const
    {
        return _heap.empty();
    }

    const T& Top()const
    {
        assert(!_heap());
        return _heap[0];
    }

    void _AdjustDown(size_t parent)
    {
        assert(parent);
        assert(!_heap.empty());
        size_t child = parent * 2 - 1;
        while (parent < _heap.size())
        {
            Compare com;
            if (child + 1<_heap.size()&& com(_heap[child + 1], _heap[child]))
            {
                ++child;
            }
            if (child<_heap.size() && com(_heap[child], _heap[parent]))
            {
                swap(_heap[child], _heap[parent]);
                parent = child;
                child = parent * 2 + 1;
            }
            else
                break;
        }
    }
    void _AdjustUp(size_t child)
    {
        assert(!_heap.empty());
        while(child)
        {
            Compare com;
            size_t parent = (child - 1) / 2;
            if (com(_heap[child], _heap[parent]))
            {
                swap(_heap[child], _heap[parent]);
                child = parent;
            }
            else
                break;
        }
    }
private:
    vector<T> _heap;
};
template<class T, class Compare = Less<T>>
class PriorityQueue
{
public:
    PriorityQueue()
    {}
    PriorityQueue(T* a, size_t size)
        :_h(a, size)
    {
    }


    void Push(const T& data)
    {
        _hp.push(data);
    }
    void Pop()
    {
        _hp.pop();
    }
    const T& Top()const
    {
        _hp.Top();
    }
    size_t Size()const
    {
        return _heap.size();
    }

    bool Empty()const
    {
        return _hp.Empty();
    }

protected:
    Heap<T, Compare> _hp;
};

文章参考:https://blog.youkuaiyun.com/qq_19656301/article/details/82490601
https://blog.youkuaiyun.com/archyli/article/details/71860651

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值