優先順序隊列Priority Queue介紹
優先順序隊列是一個擁有權值觀念的queue。它允許在底端添加元素、在頂端去除元素、刪除元素。
優先順序隊列內部的元素並不是按照添加的順序排列,而是自動依照元素的權值排列。權值最高者排在最前面。
預設情況下,優先順序隊列利用一個大頂堆完成。關於堆可以參考:STL堆詳解與編程實現
優先順序隊列以底部容器完成其所有工作,具有這種“修改某物介面,形成另一種風貌”這種性質者,成為配接器(adapter)。在STL中優先順序隊列不被歸類為容器,而被歸類為容器配接器(container
adapter)。
SGI STL中優先順序隊列定義
定義完整代碼:
template <class T, class Sequence = vector<T>, class Compare = less<typename Sequence::value_type> > class priority_queue { public: typedef typename Sequence::value_type value_type; typedef typename Sequence::size_type size_type; typedef typename Sequence::reference reference; typedef typename Sequence::const_referenceconst_reference; protected: Sequence c; //底層容器 Compare comp;//元素大小比較標準 public: priority_queue() : c() {} explicit priority_queue(const Compare& x) : c(), comp(x) {} //以下用到的 make_heap(), push_heap(), pop_heap()都是泛型演算法 //注意,任一個建構式都立刻於底層容器內產生一個 implicit representation heap。 template <class InputIterator> priority_queue(InputIterator first, InputIterator last, const Compare& x) : c(first, last), comp(x) {make_heap(c.begin(), c.end(), comp); } template <class InputIterator> priority_queue(InputIterator first, InputIterator last) : c(first, last) { make_heap(c.begin(), c.end(), comp); } bool empty() const { return c.empty(); } size_typesize() const { return c.size(); } const_referencetop() const { return c.front(); } void push(const value_type& x) { __STL_TRY { // push_heap是泛型演算法,先利用底層容器的 push_back() 將新元素 // 推入端,再重排 heap。見 C++ Primer p.1195。 c.push_back(x); push_heap(c.begin(), c.end(), comp);// push_heap是泛型演算法 } __STL_UNWIND(c.clear()); } void pop() { __STL_TRY { // pop_heap 是泛型演算法,從 heap 內取出一個元素。它並不是真正將元素 // 彈出,而是重排 heap,然後再以底層容器的 pop_back() 取得被彈出 // 的元素。見 C++ Primer p.1195。 pop_heap(c.begin(), c.end(), comp); c.pop_back(); } __STL_UNWIND(c.clear()); } };
優先順序隊列編程實現(C Plus Plus)
在這裡自己用C++編程實現了簡易版的優先順序隊列。其中用到了前一篇部落格裡面的堆heap.h:
//STL堆演算法實現(大頂堆)//包含容器vector的標頭檔:Heap用vector來儲存元素#include <vector>#include <iostream>#include <functional>#define MAX_VALUE 999999 //某個很大的值,存放在vector的第一個位置(最大堆)const int StartIndex = 1;//容器中堆元素起始索引using namespace std;//堆類定義//預設比較規則lesstemplate <class ElemType,class Compare = less<ElemType> >class MyHeap{private:vector<ElemType> heapDataVec;//存放元素的容器int numCounts;//堆中元素個數Compare comp;//比較規則public:MyHeap();vector<ElemType>& getVec();void initHeap(ElemType *data,const int n);//初始化操作void printfHeap();//輸出堆元素void makeHeap();//建堆void sortHeap();//堆排序演算法void pushHeap(ElemType elem);//向堆中插入元素void popHeap();//從堆中取出堆頂的元素void adjustHeap(int childTree,ElemType adjustValue);//調整子樹void percolateUp(int holeIndex,ElemType adjustValue);//上溯操作void setNumCounts(int val);//設定當前所要構建的堆中元素個數};template <class ElemType,class Compare>MyHeap<ElemType,Compare>::MyHeap():numCounts(0){heapDataVec.push_back(MAX_VALUE);}template <class ElemType,class Compare>vector<ElemType>& MyHeap<ElemType,Compare>::getVec(){return heapDataVec;}template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::initHeap(ElemType *data,const int n){//拷貝元素資料到vector中for (int i = 0;i < n;++i){heapDataVec.push_back(*(data + i));++numCounts;}}template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::printfHeap(){cout << "Heap : ";for (int i = 1;i <= numCounts;++i){cout << heapDataVec[i] << " ";}cout << endl;}template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::makeHeap(){//建堆的過程就是一個不斷調整堆的過程,迴圈調用函數adjustHeap依次調整子樹if (numCounts < 2)return;//第一個需要調整的子樹的根節點多音int parent = numCounts / 2;while(1){adjustHeap(parent,heapDataVec[parent]);if (StartIndex == parent)//到達根節點return;--parent;}}template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::sortHeap(){//堆排序思路//每執行一次popHeap操作,堆頂的元素被放置在尾端,然後針對前面的一次再執行popHeap操作//依次下去,最後即得到排序結果while(numCounts > 0)popHeap();}template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::pushHeap(ElemType elem){//將新元素添加到vector中heapDataVec.push_back(elem);++numCounts;//執行一次上溯操作,調整堆,以使其滿足最大堆的性質percolateUp(numCounts,heapDataVec[numCounts]);}template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::popHeap(){//將堆頂的元素放在容器的最尾部,然後將尾部的原元素作為調整值,重建堆ElemType adjustValue = heapDataVec[numCounts];//堆頂元素為容器的首元素heapDataVec[numCounts] = heapDataVec[StartIndex];//堆中元素數目減一--numCounts;adjustHeap(StartIndex,adjustValue);}//調整以childTree為根的子樹為堆template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::adjustHeap(int childTree,ElemType adjustValue){//洞節點索引int holeIndex = childTree;int secondChid = 2 * holeIndex + 1;//洞節點的右子節點(注意:起始索引從1開始)while(secondChid <= numCounts){if (comp(heapDataVec[secondChid],heapDataVec[secondChid - 1])){--secondChid;//表示兩個子節點中值較大的那個}//上溯heapDataVec[holeIndex] = heapDataVec[secondChid];//令較大值為洞值holeIndex = secondChid;//洞節點索引下移secondChid = 2 * secondChid + 1;//重新計算洞節點右子節點}//如果洞節點只有左子節點if (secondChid == numCounts + 1){//令左子節點值為洞值heapDataVec[holeIndex] = heapDataVec[secondChid - 1];holeIndex = secondChid - 1;}//將調整值賦予洞節點heapDataVec[holeIndex] = adjustValue;//此時可能尚未滿足堆的特性,需要再執行一次上溯操作percolateUp(holeIndex,adjustValue);}//上溯操作template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::percolateUp(int holeIndex,ElemType adjustValue){//將新節點與其父節點進行比較,如果索引值比其父節點大,就父子交換位置。//如此,知道不需要對換或直到根節點為止int parentIndex = holeIndex / 2;while(holeIndex > StartIndex && comp(heapDataVec[parentIndex],adjustValue)){heapDataVec[holeIndex] = heapDataVec[parentIndex];holeIndex = parentIndex;parentIndex /= 2;}heapDataVec[holeIndex] = adjustValue;//將新值放置在正確的位置}template <class ElemType,class Compare>void MyHeap<ElemType,Compare>::setNumCounts(int val){numCounts = val;}
PriorityQueue.h:
#include "Heap.h"//優先順序隊列類定義//預設:值最小的權值最大template <class ElemType,class Compare = less<ElemType> >class MyPriorityQueue{private:MyHeap<ElemType,Compare> heap;//底層用堆實現public://建構函式MyPriorityQueue(ElemType *data,int n);//判斷優先順序隊列是否為空白int empty(){return heap.getVec().size() - 1;}//返回優先順序隊列大小long size(){return heap.getVec().size() - 1;}//注意底層容器第一個元素是無效元素//取得優先順序隊列頭元素ElemType top(){return heap.getVec()[StartIndex];}//添加元素void push(const ElemType &val);//彈出隊首元素void pop();MyHeap<ElemType,Compare>& getHeap(){return heap;};};template <class ElemType,class Compare>MyPriorityQueue<ElemType,Compare>::MyPriorityQueue(ElemType *data, int n){heap.initHeap(data,n);heap.makeHeap();heap.sortHeap();}template <class ElemType,class Compare>void MyPriorityQueue<ElemType,Compare>::push(const ElemType &val){heap.setNumCounts(heap.getVec().size() - 1);//排除容器首部的哨兵元素heap.makeHeap();heap.pushHeap(val);heap.sortHeap();}template <class ElemType,class Compare>void MyPriorityQueue<ElemType,Compare>::pop(){heap.getVec().erase(heap.getVec().begin() + 1);//刪除隊列首部的元素heap.setNumCounts(heap.getVec().size() - 1);//排除容器首部的哨兵元素heap.makeHeap();heap.sortHeap();}
PriorityQueueTest.cpp:
#include "PriorityQueue.h"#include <iostream>#include <string>using namespace std;int main(){const int n = 9;int data[n] = {0,1,2,3,4,8,9,3,5};MyPriorityQueue<int> *priorityObj1 = new MyPriorityQueue<int>(data,n);cout << "Current Heap: " << endl;for (int i = 1;i <= priorityObj1->size();++i){cout << priorityObj1->getHeap().getVec()[i] << " ";}cout << endl;cout << "Size = " << priorityObj1->size() << endl;cout << "Top element = " << priorityObj1->top() << endl;priorityObj1->pop();cout << "After pop one element:" << endl;cout << "Size = " << priorityObj1->size() << endl;cout << "Top element = " << priorityObj1->top() << endl;cout << "Current Heap: " << endl;for (int i = 1;i <= priorityObj1->size();++i){cout << priorityObj1->getHeap().getVec()[i] << " ";}cout << endl;priorityObj1->pop();cout << "After pop one element:" << endl;cout << "Size = " << priorityObj1->size() << endl;cout << "Top element = " << priorityObj1->top() << endl;cout << "Current Heap: " << endl;for (int i = 1;i <= priorityObj1->size();++i){cout << priorityObj1->getHeap().getVec()[i] << " ";}cout << endl;priorityObj1->push(7);cout << "After push one element 7:" << endl;cout << "Size = " << priorityObj1->size() << endl;cout << "Top element = " << priorityObj1->top() << endl;cout << "Current Heap: " << endl;for (int i = 1;i <= priorityObj1->size();++i){cout << priorityObj1->getHeap().getVec()[i] << " ";}cout << endl;delete priorityObj1;}
運行結果(Win7 + VS2008):