STL 之 优先队列(priority_queue)

  转载自:

      https://blog.csdn.net/luomingjun12315/article/details/47376359

 

1、什么是优先队列

       能够完成下列两种操作的数据结构,我们便称之为优先队列。

       ①插入一个数值    ②取出最大(或者最小)的数值(获取数值,并且删除)。

       从严格意义上来说优先队列,并不是队列,因为它并不遵循队列的FIFO(先进先出的原则)。

2、实现优先队列

      我们可以使用一种叫做“堆(heap)”的数据结构来实现优先队列。堆有一个重要的性质就是儿子的值一定不小于父亲。除此之外,树的节点是从上到下、从左到右的顺序紧凑排列的。堆就是如下图的二叉树, 不知道是什么是二叉树的同学请移步:传送门

        我们向堆插入数值时,首先我们先在堆的尾部插入该值,然后再根据大小关系不断的提升它的位置

 

       删除堆的最小值时,首先把堆的最后一个节点复制到根节点上,然后删除最后一个节点。之后我们根据大小关系不断和交换位置,使其满足堆的定义。

        堆的这两种操作所用的时间,和树的深度成正比。我们不难发现堆的时间复杂度为O(log n).

       现在我们就可以来实现堆了,为了简单一些我们使用数组来实现:

 

  1.  
    int heap[MAXN], size_heap = 0;
  2.  
    //插入数值
  3.  
    void push(int x){
  4.  
    int i = size_heap++;
  5.  
    while(i > 0){
  6.  
    //父节点的编号
  7.  
    int p = (i-1)/2;
  8.  
    //如果大小关系满足,则退出循环
  9.  
    if(heap[p] <= x) break;
  10.  
    //将父节点放下,把自己向上提
  11.  
    heap[i] = heap[p];
  12.  
    i = p;
  13.  
    }
  14.  
    heap[i] = x;
  15.  
    }
  16.  
    //获取最小值,并删除最小值
  17.  
    int top(){
  18.  
    //最小值
  19.  
    int ret = heap[0];
  20.  
    //最后一个节点
  21.  
    int x = heap[--size_heap];
  22.  
    int i = 0;
  23.  
    while(2*i+1 < size_heap){
  24.  
    int a = 2*i+1, b = 2*i+2;
  25.  
    //比较两个儿子的值
  26.  
    if(b < size_heap && heap[b] < heap[a]) a = b;
  27.  
    //满足大小关系
  28.  
    if(heap[a] >= x) break;
  29.  
    //将数值小的那个儿子提上来
  30.  
    heap[i] = heap[a];
  31.  
    i = a;
  32.  
    }
  33.  
    heap[i] = x;
  34.  
     
  35.  
    return ret;
  36.  
    }

 

 

     通过实现堆,我们就大致的对优先队列的原理有了一定的了解。

3、STL之priority_queue

       然而很多时候我们并不需要自己实现堆。C++为我们提供了模板类priority_queue。STL的priority_queue包含在头文件queue中, 由于priority_queue使用堆实现,所以我们可以知道priority_queue的时间复杂度应该也为 O(log n)。不过和上述堆实现的优先队列有些许不同。因为priority_queue取出数值时是最大值。我们来看看priority_queue的用法。

<1>priority_queue的基本操作

      priority_queue我们常用的有四个成员函数分别

bool empty() const; 返回值为true,则该优先队列为空,反之亦然
size_type size() const; 返回优先队列中元素的数量,size_type是unsigned integral type
void pop(); 删除队列顶部的元素,也就是根节点
void push (const value_type& val); 将元素加入,优先队列中
const_reference top() const; 返回队列顶部的元素,const_reference为队列顶部的类型

<2>改变priority_queue中的排列顺序

      在很多时候,我们需要的不一定是最大值,也有可能是最小值。这是就需要我们来改变priority_queue中的顺序。方法有两种:

      ①如果加入优先队列的是基本类型,那么我们就可以这样,我们以int为例:

  1.  
    //注意greater<int> >这之间有一个空格
  2.  
    priority_queue<int, vector<int>, greater<int> >Q;

     ②对于自定义数据类型的话,我们不论是要改变排序方式,还是不改变都要这样 --  重载 小于( < ) 运算符:

        因为,如果你不重载比较运算符的话,编译器无法比较自定义数据类型的大小关系。然而又因为在priority_queue的内部,只需用到 小于号(<),所以我们只需要重载小于号即可。当然对于自定义数据类型来说,也是必须重载,否则将无法使用priority_queue。重载小于号,我们可以有两种方式,一种用成员函数,一种使用友元函数(这里就不多说了,不会的同学,自己在好好复习复习C++)。

注意:如果使用成员函数重载小于号的话,那么要将重载函数变为常成员函数,否则将无法通过编译。

        初步的了解了优先队列之后,我们就可以来两道题巩固,巩固。Expedition, FenceRepair。这两道都是非常有意思的题目,思路比较奇特。

 

posted @ 2018-08-03 15:08  博客园—哆啦A梦  阅读(339)  评论(0)    收藏  举报