1. 程式人生 > >C++模板連結串列實現優先順序佇列

C++模板連結串列實現優先順序佇列

本文是承接我的上一篇文章,只是將普通佇列增加了優先順序.實現了一個優先順序佇列.本文采取的優先順序佇列的實現方式在於資料增加優先順序標誌位,在資料進入佇列時,根據優先順序排序的順序進入,出佇列仍然是從頭出.使用該種思想實現的優先順序佇列.

  1. 開始時犯了一個錯誤,在子類中定義PriorityQueueLinkList<T, capacity> *linkList = NULL;這樣,繼承過來的方法isEmpty(), isFull()等中使用的linkList仍是父類的linkList,造成錯誤.原因是,C++編譯器會先構造父類結構,之後再構造子類結構.而繼承過來的函式在構造父類的時候就確定了.其並不知道子類的成員變數,因此就無法訪問. 總之,這裡要注意,繼承過來的父類的成員函式(public, protected)在子類中可以使用,但是如果成員函式呼叫了成員變數,該成員變數也需要在子類中被繼承才行(如果成員變數在父類中是privated的就會有問題,子類中從新定義同名成員變數沒有任何作用也不可能有任何作用).

  2. 對繼承來的父類的linkList,在子類中可以使用強制型別轉換.將其轉換為PriorityQueueLinkList. 這樣做是安全的,因為傳入的data本來必須要保證是優先順序佇列中的結點的資料結構.((PriorityQueueLinkList<T, capacity>*)linkList)->enqueueWithPriority(data);

  3. 關鍵資料結構PriorityQueueLinkList,繼承自QueueLinkList. 重新寫enque方法.並利用C++的隱藏,將尾插入方法隱藏,因為優先順序佇列不適用尾插入暴露在外面. 出佇列方法則可以直接使用繼承自父類的dequeue.

  4. 該佇列插入的效率有一定問題,在佇列超過10000個元素後,插入效率明顯降低.後續考慮使用高效的插入演算法進行優化比較.

6.補充一點C++繼承過程中基類與派生類指標相互強制轉換的知識. 如果開始的指標指向父類,之後強制轉換成子類的指標,則通過該指標可以操作子類獨有的成員函式(包括子類新寫的與子類繼承後重寫/隱藏的). 但如果父類是虛擬函式,則不管子類是否覆蓋,通過該強制轉換的指標訪問該函式,仍然是訪問的父類函式. 如果開始指標指向子類,將其強制轉換為父類指標,則子類新寫的函式不可見.但被覆蓋過的虛擬函式除外.該指標操作父類的虛擬函式,會自動呼叫子類的對應函式(多型).

template<typename
T, unsigned int capacity> class PriorityLinkQueue : public LinkQueue<T, capacity> { public: PriorityLinkQueue(); ~PriorityLinkQueue(); bool enQueue(T data); //private: // PriorityQueueLinkList<T, capacity> *linkList = NULL; };
template <typename T, unsigned int capacity>
PriorityLinkQueue<T, capacity>::PriorityLinkQueue()
{

}

template <typename T, unsigned int capacity>
PriorityLinkQueue<T, capacity>::~PriorityLinkQueue()
{
    cout << "PriorityLinkQueue destructor called" << endl;
}

template <typename T, unsigned int capacity>
bool PriorityLinkQueue<T, capacity>::enQueue(T data)
{
    /*開始時犯了一個錯誤,在子類中定義PriorityQueueLinkList<T, capacity> *linkList = NULL;
    這樣,繼承過來的方法isEmpty(), isFull()等中使用的linkList仍是父類的linkList,造成錯誤.
    原因是,C++編譯器會先構造父類結構,之後再構造子類結構.而繼承過來的函式在構造父類的時候
    就確定了.其並不知道子類的成員變數,因此就無法訪問.*/
    return ((PriorityQueueLinkList<T, capacity>*)linkList)->enqueueWithPriority(data);
}
template <typename T, const unsigned int capacity>
class PriorityQueueLinkList : public QueueLinkList<T, capacity>
{
public:
    PriorityQueueLinkList();
    ~PriorityQueueLinkList();
    bool enqueueWithPriority(T data);
private:
    bool enqueueAtTail(T data);  //利用C++的隱藏,將尾插入方法隱藏,因為優先順序佇列不適用尾插入暴露在外面
};
template<typename T, const unsigned int capacity>
PriorityQueueLinkList<T, capacity>::PriorityQueueLinkList()
{

}

template<typename T, const unsigned int capacity>
PriorityQueueLinkList<T, capacity>::~PriorityQueueLinkList()
{
    cout << "PriorityQueueLinkList destructor called" << endl;
}



template<typename T, const unsigned int capacity>
bool PriorityQueueLinkList<T, capacity>::enqueueWithPriority(T data)
{
    bool rs = false;
    if (isFull())
    {
        rs = false;
    }
    else
    {
        if (isEmpty())
        {
            LinkNode<T> *node = new LinkNode<T>();
            node->data = data;
            node->next = NULL;
            head->next = node;
            tail = node;
            linkNodeNum++;
            rs = true;
        }
        else
        {
            LinkNode<T> *iter = head->next;
            LinkNode<T> *preIter = head;
            while (NULL != iter)
            {
                unsigned int priority = iter->data.priority;
                if (data.priority >= priority)
                {
                    preIter = iter;
                    iter = iter->next;
                }
                else
                {
                    //insert after preIter and before iter
                    LinkNode<T> *node = new LinkNode<T>();
                    node->data = data;
                    preIter->next = node;
                    node->next = iter;
                    linkNodeNum++;
                    rs = true;
                    break;
                }
            }
            if (NULL == iter)
            {
                rs = enqueueAtTail(data);
            }
        }
    }
    return rs;
}


template<typename T, const unsigned int capacity>
bool PriorityQueueLinkList<T, capacity>::enqueueAtTail(T data)
{
    return QueueLinkList<T, capacity>::enqueueAtTail(data);     //預設實現,目的在於隱藏該方法
}

測試程式碼如下:

void testPriorityQueue()
{
    PriorityLinkQueue<PriorityQueueNode<int>, 30000> *priorityLinkQueue = new PriorityLinkQueue<PriorityQueueNode<int>, 30000>();

    unsigned int num = 0;
    while (num<2)
    {
        num++;
        cout << "NUM:" << num << endl;
        for (int i = 0; i < 40000; i++)
        {
            PriorityQueueNode<int> prioQueueNode;
            prioQueueNode.priority = (i % 5);
            prioQueueNode.data = i;

            priorityLinkQueue->enQueue(prioQueueNode);
        }

        _sleep(2000);

        for (int i = 0; i < 35000; i++)
        {
            PriorityQueueNode<int> deQueueNode;
            priorityLinkQueue->deQueue(deQueueNode);
        }

        _sleep(2000);
    }

    for (int i = 0; i < 40000; i++)
    {
        PriorityQueueNode<int> prioQueueNode;
        prioQueueNode.priority = (i % 5);
        prioQueueNode.data = i;

        priorityLinkQueue->enQueue(prioQueueNode);
    }

    delete priorityLinkQueue;
    priorityLinkQueue = NULL;
}