數據結構——基於數組的優先級隊列模板類實現

數據結構筆記3.4
與普通的隊列不同,優先級隊列並不一定按照FIFO(先進先出)的原則對數據進行操縱,而是每次從隊列取出具有最高優先權的元素。打個比方,你現在有一堆任務,而你只能一項一項的完成,一種方式是哪項任務先來的你完成哪個;另一種方式是你考慮了各項任務的輕重緩急,然後給他們各自一個優先級序號(就是執行先後次序的序號),你按照這個執行序號來完成每一項任務。這其實就好比是,兩種隊列的差別。
優先級隊列包括最小優先級隊列和最大優先級隊列(就是出隊元素是按由小到大出,還是由大到小出),這裏實現的是最小優先級隊列,最大的與之類似。
而爲什麼說是基於數組的優先級隊列,當然,這是因爲還可以利用堆(heap)堆優先級隊列進行存儲表示,這在後續會有相應的文章。這裏給出用數組存儲優先級隊列的代碼,如有不當之處,歡迎各位指正!
注意的問題:在實現這個類的時候,關鍵的函數是adjust,他在每次進入隊新元素的時候都會調用一次,所以其實每次都是在一個已經有序的數列中插入新的元素(注意區分與數組排序的不同),所以在實現的時候也會有不同。
算法性能分析:在對數據進行操作的時候涉及到進隊函數Insert和出隊函數RemoveMin,進隊函數的的時間複雜度(爲保持數據始終有序,需要用adjust函數對整個數組的元素比較和移動)爲:最好的情況進入隊列的數據就是整個隊中的最大值,這時候不需要移動,最壞的情況是進入的是最小值,這時候需要比較並移動n + 1次(即元素的數量次)。而每次出隊一個數據,也需要其後面的所有數據都向前移動進行填補(節約數組空間)。綜上,算法的時間複雜度爲O(n)。後續我會介紹用heap實現,會將時間複雜度提升到對數級別。下面貼出代碼:
基於數組的優先級隊列模板class

//數據結構——基於數組的優先級隊列
#include <iostream>
#include <cassert>
using namespace std;
const int DefaultPQSize = 50;           //優先級隊列數組的默認長度
//優先級隊列類定義
template<class T>
class PQueue {
public:
    PQueue(int sz = DefaultPQSize);     //構造函數
    ~PQueue();                         //析構函數
    bool Insert(const T & x);           //將新元素x插入到隊尾
    bool RemoveMin(T & x);              //將隊頭元素刪除
    bool GetFront(T & x) const;         //讀取隊頭元素,具有優先權最小的值
    void MakeEmpty();                   //設置優先級隊列爲NULL
    bool IsEmpty() const;               //判斷優先級隊列是否爲NULL
    bool IsFull() const;                //判斷優先級隊列是否已FULL
    int GetSize() const;                //求優先級隊列中元素的個數
    void Output();                      //隊列輸出函數
protected:
    T *pqElements;                      //優先級隊列數組
    int count;                          //當前元素的個數(計數器)
    int maxSize;                        //優先級隊列最大可容納元素的個數
    void adjust();                      //隊列調整
};
//類的函數實現
template<class T>
PQueue<T>::PQueue(int sz) {
    //構造函數,建立一個最大具有maxSize元素的NULL的優先級隊列
    maxSize = sz;
    count = 0;
    pqElements = new T[maxSize];        //開闢隊列空間
    assert(pqElements != NULL);         //斷言:檢驗是否空間分配成功
}

template<class T>
PQueue<T>::~PQueue() {
    //析構函數,釋放程序所佔用的資源
    delete[] pqElements;
}

template<class T>
bool PQueue<T>::Insert(const T & x) {
    //若優先級隊列不FULL,則將元素插入到隊列的隊尾,否則返回false
    if (count == maxSize) {             //隊列已滿返回false
        return false;
    }
    pqElements[count] = x;              //隊列不滿,將x插入到隊尾
    count++;
    adjust();                           //對隊列進行權值調整
    return true;                        
}

template<class T>
void PQueue<T>::adjust() {
    //將隊列元素按其優先級大小調整,保持所有元素按照從小到大有序
    //始終向一個有序數列中插入元素,注意這裏並不是對整個數組排序
    T temp = pqElements[count - 1];     //新插入的元素賦值給temp
    for (int j = count - 2; j >= 0; j --) {
        if (pqElements[j] <= temp) {
            break;                      //因爲原來的序列已經是有序的,所以只與最後一個元素比較即可
        }
        else {
            pqElements[j + 1] = pqElements[j];
            pqElements[j] = temp;       //插入到合適的位置,並繼續循環
        }
    }
}

template<class T>
bool PQueue<T>::RemoveMin(T & x) {
    //若隊列不爲NULL則函數返回具有最大優先權(即最小值)的值,
    //並且刪除該元素
    if (0 == count) {                   //優先級隊列爲NULL,返回錯誤
        return false;
    }
    x = pqElements[0];
    //運用元素覆蓋的方式刪除第一個元素(注意下標爲0)
    for (int i = 0; i < count - 1; i ++) {
        pqElements[i] = pqElements[i + 1];
    }
    count--;                            //隊列元素總數目減1
    return true;
}

template<class T>
bool PQueue<T>::GetFront(T & x) const {
    //若優先級隊列不爲NULL,則返回最大優先級的元素
    if (0 == count) {
        return false;
    }
    x = pqElements[0];
    return true;
}

template<class T>
bool PQueue<T>::IsEmpty() const{
    if (0 == count) {
        return true;
    }
    else {
        return false;
    }
}

template<class T>
bool PQueue<T>::IsFull() const {
    if (count == maxSize) {
        return true;
    }
    else {
        return false;
    }
}

template<class T>
void PQueue<T>::MakeEmpty() {
    //設置優先級隊列爲NULL
    count = 0;
}

template<class T>
int PQueue<T>::GetSize() const {
    return count;
}

template<class T>
void PQueue<T>::Output() {
    //按照優先級輸出隊列中的所有元素
    for (int i = 0; i < count; i ++) {
        cout << pqElements[i] << ' ';
    }
    cout << endl;
}

Main函數演示代碼:

int main()
{
    PQueue<int> pqueue;
    pqueue.Insert(5);
    pqueue.Insert(3);
    pqueue.Insert(4);
    pqueue.Insert(2);
    pqueue.Insert(7);
    pqueue.Output();        //此時可以看到隊列已經有序
    int min_1, min_2;
    pqueue.RemoveMin(min_1);
    pqueue.RemoveMin(min_2);
    pqueue.Output();        //此時可以看到出隊的並非最先插入的元素,而是具有最高優先級的元素

    system("pause");
    return 0;
}

運行效果圖:
這裏寫圖片描述

發佈了50 篇原創文章 · 獲贊 228 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章