priority_queue优先级队列实现

优先级队列的实现

优先级队列,并不遵守先进先出的特性,所以可以说它并不是一个队列。尽管名字上有些想象。优先级队列,主要的特性就是,对存在里面的数据有了一个优先级高低的划分,或者大的优先级高,或者小的优先级高,出队时就根据优先级的高低进行出队。

跟据它的出入队特性,我们可以使用堆来对其进行构建。堆在物理结构上是一个连续的数组,可以支持下标的随机访问,而在逻辑上是一颗完全二叉树。通过构建大堆或者小堆完全满足它的按优先级最高的出队的要求,每次只需出堆顶的元素是即可。

pop

它的pop与其他的容器用法一样,只不过它出的是队列之中优先级较高的数据。

每次pop时要求出优先级最高的数据,这里先假定大的数优先级高。我们需要构建一个大堆,每次出堆顶的元素即可。

  • 先将堆顶元素与最后一个元素交换位置
  • 再将最后一个位置的元素pop掉
  • 再重新向下调整成为堆
push

插入是个关键,我们需要插入每个元素后,都能保证它是一个堆,以便后面的操作

在最开始时,队列为空,所以我们只需要插入每一个后都维持其为大堆或者小堆。

  • 先将元素尾插进底层容器
  • 再将该元素进行向上调整成为堆
top

我们只需每次取出堆顶的元素即可,就是数组下标为0的元素。

实现代码:

#ifndef __PRIORITY_QUEUE_HPP__
#define __PRIORITY_QUEUE_HPP__ 

#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
/*
 *优先级队列: 根据出入的第三个模板参数,来确定是大的数为优先级高,还是小的优先级高
 *  pop时 每次pop出队列中最的或最小的数
 *  top时 top出最大或最小的数 
 * */


/*  通过构建堆来完成pop 与 top 的操作。
 *  vector 相当于一颗完全二叉树 ,可以通过下标随机访问,用来构建堆最合适
 * */


/*
 *使用仿函数来调整队列中的优先级
 */

template<class T>
class Less{  //大的优先级高,降序排列

  public:
    bool operator()(const T& a1, const T& a2)
    {
      return a1 > a2;
    }
};

template<class T> 
class Greater{  //小的优先级高,升序排列
  public:
    bool operator()(const T& a1,const T& a2)
    {
      return a1 < a2;
    }
};

template<class T,class Container = std::deque<T> , class Compare = Less<T>>
class PriorityQueue{  //此时默认为less 大的数优先级高,只需在传入模板参数时进行选择即可
  public:
    void Push(const T& value)
    {
      _con.push_back(value); //插入到数组后最后一个位置
      Adjustup(_con.size()-1);   //再将数据向上调整重新构成堆
    }

    void Pop()
    {
      std::swap(_con[0],_con[_con.size()-1]);   //使堆顶元素与最后一个元素交换位置,
      _con.pop_back();  //再将最后一个元素删除
      Adjustdown();     //再从堆顶开始将其调整为堆
    }

    T& top()  //取出堆顶的元素
    {
      return _con[0];
    }

    void Adjustup(int n)  //向上调整
    {
      Compare _com;
      int child = n;
      int parent = (child - 1 ) / 2;
      while(child > 0)  //当调整到堆顶元素时就停止
      {
        if(_com(_con[child] , _con[parent]))
          std::swap(_con[parent],_con[child]);

        child = parent;
        parent = (child - 1 ) / 2 ; 
        
      }
    }

    void Adjustdown()  //向下调整
    {
      Compare _com;
      int parent = 0;
      int child = parent * 2 + 1;
      while(child < _con.size())
      {
        if(child +1  < _con.size() && _com(_con[child + 1] , _con[child]))
          child = child + 1;  //选两个孩子中较大的一个

        if(_com(_con[child] , _con[parent]))  //和双亲节点比较
          std::swap(_con[child] , _con[parent]);
        else break;

        parent = child;
        child = parent * 2 + 1;
      }
    }

    size_t Size()
    {
      return _con.size();
    }

    bool Empty()
    {
      return _con.empty();
    }

  private:
    Container _con;
};


# endif 

猜你喜欢

转载自blog.csdn.net/M_jianjianjiao/article/details/84782538