優先隊列的實現(大根堆,小根堆)


  本博客不講解具體的原理,僅僅給出一種優先隊列較為一般化的,可重用性更高的一種實現方法。我所希望的是能過帶來一種與使用STL相同的使用體驗,因為學習了STL源碼之后深受STL代碼的影響,對每個ADT都希望能過給出一種高效,可重用,更一般的實現方法,即使我的代碼在STL的priority_queue面前僅僅只是三流水平,但也足夠吧二叉堆這種數據結構演繹好了。為了更一般化,我拋棄C語言的函數指針,改用STL相同的仿函數來實現更加方便的自定義優先級比較函數,於此同時我也兼容了已有類型的原有優先級比較仿函數。首先給出maxPriorityQueue的ADT以及默認的優先級比較仿函數,默認為大根堆,小根堆重載優先級比較仿函數即可。

#ifndef MAXPRIORITYQUEUE_H #define MAXPRIORITYQUEUE_H #include <cstring> template<class T>
struct Compare { bool operator () (const T& a, const T& b) { return a < b; } }; template<>
struct Compare<char*> { bool operator () (char* s1, char* s2) { return strcmp(s1, s2) < 0; } }; template<class T>
class maxPriorityQueue { public: ~maxPriorityQueue() {} virtual bool empty() const = 0; virtual int size() const = 0; virtual T& top() = 0; virtual void pop() = 0; virtual void push(const T& theElement) = 0; }; #endif 

  對於ADT的設計與實現,在C++中,相應ADT的純虛類是必不可少的,它是ADT的邏輯定義,是設計數據結構的基礎,上述代碼給出了maxPriorityQueue的定義以及默認優先級比較仿函數,對於仿函數的使用方法,可在下面的maxHeap類中找到。

 

#include "maxPriorityQueue.h" #include <cstdlib> #include <cstdio> #include <algorithm> #ifndef MAX_HEAP_H #define MAX_HEAP_H


/* 用法:大根堆重載小於號,小根堆重載大於號 */ template<class T, class Cmp = Compare<T> >
class maxHeap : maxPriorityQueue<T> { public: maxHeap(int Size = 10) { heap = new T[Size]; Heapsize = 0; Arraylength = Size; } maxHeap(maxHeap<T, Cmp>& theHeap); ~maxHeap(); void Initialize(T* theHeap, int heapsize); bool empty() const; int size() const; void push(const T& x); void pop(); T& top() { return heap[1]; } private: void changelength1(); protected: T* heap; int Heapsize; int Arraylength; Cmp elecmp; }; template<class T, class Cmp>
void maxHeap<T, Cmp>::changelength1() { T* newHeap = new T[Arraylength * 2]; std::copy(heap, heap + Arraylength, newHeap); delete [] heap; heap = newHeap; } template<class T, class Cmp>
bool maxHeap<T, Cmp>::empty() const { return Heapsize == 0; } template<class T, class Cmp>
int maxHeap<T, Cmp>::size() const { return Heapsize; } template<class T, class Cmp>
void maxHeap<T, Cmp>::push(const T& x) { if(Heapsize == Arraylength - 1) { changelength1(); Arraylength *= 2; } int currentNode = ++Heapsize; while(currentNode != 1 && elecmp(heap[currentNode / 2], x)) { heap[currentNode] = heap[currentNode / 2]; currentNode /= 2; } heap[currentNode] = x; } template<class T, class Cmp>
void maxHeap<T, Cmp>::pop() { if(Heapsize == 0){ printf("error at function maxHeap<T, Com>::pop()\n"); exit(-1); } heap[1].~T(); T lastElement = heap[Heapsize--]; int currentNode = 1, child = 2; while(child <= Heapsize) { if(child < Heapsize && elecmp(heap[child], heap[child + 1])) child++; if(!elecmp(lastElement, heap[child])) break; heap[currentNode] = heap[child]; currentNode = child; child *= 2; } heap[currentNode] = lastElement; } template<class T, class Cmp>
void maxHeap<T, Cmp>::Initialize(T* theHeap, int heapsize) { delete [] heap; heap = new T[heapsize + 1]; std::copy(theHeap, theHeap + heapsize + 1, heap); Heapsize = heapsize; Arraylength = heapsize + 1; for(int root = Heapsize / 2; root >= 1; root--) { T rootElement = heap[root]; int child = root * 2; while(child <= Heapsize) { if(child < Heapsize && elecmp(heap[child], heap[child + 1])) child++; if(!elecmp(rootElement, heap[child])) break; heap[child / 2] = heap[child]; child *= 2; } heap[child / 2] = rootElement; } } template<class T, class Cmp> maxHeap<T, Cmp>::~maxHeap() { delete [] heap; } template<class T, class Cmp> maxHeap<T, Cmp>::maxHeap(maxHeap<T, Cmp>& theHeap) { Arraylength = theHeap.Arraylength; Heapsize = theHeap.Heapsize; elecmp = theHeap.elecmp; heap = new T[Arraylength]; std::copy(theHeap.heap, theHeap.heap + Arraylength, heap); } #endif

   例如maxHeap中保護成員elecmp(意思可以理解為Element Comparison)為一個仿函數的具體類,Cmp為仿函數的類型,使用方法為

    Cmp elecmp;
    elecmp(a, b)

  雖然這個類叫做maxHeap,但它不僅支持大根堆,還支持小根堆,maxHeap中沒有一些clear() 等操作,也沒有制作相關的迭代器,因為heap理論上來講不需要遍歷,但是其他的數據結構我都會設計相關的迭代器,只是有時候會偷點懶。

  

TIP:1. 內存擴展函數應定義為私有或保護函數,不推薦定義為友函數。

    2. Initialize操作更准確的復雜度為Θ(n)。

   3. 在頭文件中不推薦聲明STL的命名空間。

 

  最后歡迎學習交流,做題時遇到優先隊列的題我的maxHeap過不了但priority_queue過得了,第一個我請杯奶茶,我自認為比不可能有bug。

 

 

參考文獻:[1] [美]Sartaj Sahni著,王立柱 劉志紅 譯,《數據結構、算法與應用(C++語言描述, 第二版)》,2021.3.26

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM