priority_queue優先順序佇列實現
阿新 • • 發佈:2019-01-13
優先順序佇列的實現
優先順序佇列,並不遵守先進先出的特性,所以可以說它並不是一個佇列。儘管名字上有些想象。優先順序佇列,主要的特性就是,對存在裡面的資料有了一個優先順序高低的劃分,或者大的優先順序高,或者小的優先順序高,出隊時就根據優先順序的高低進行出隊。
跟據它的出入隊特性,我們可以使用堆來對其進行構建。堆在物理結構上是一個連續的陣列,可以支援下標的隨機訪問,而在邏輯上是一顆完全二叉樹。通過構建大堆或者小堆完全滿足它的按優先順序最高的出隊的要求,每次只需出堆頂的元素是即可。
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