1. 程式人生 > >priority_queue優先順序佇列實現

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