C++模板連結串列實現優先順序佇列
本文是承接我的上一篇文章,只是將普通佇列增加了優先順序.實現了一個優先順序佇列.本文采取的優先順序佇列的實現方式在於資料增加優先順序標誌位,在資料進入佇列時,根據優先順序排序的順序進入,出佇列仍然是從頭出.使用該種思想實現的優先順序佇列.
開始時犯了一個錯誤,在子類中定義
PriorityQueueLinkList<T, capacity> *linkList = NULL;
這樣,繼承過來的方法isEmpty(), isFull()等中使用的linkList仍是父類的linkList,造成錯誤.原因是,C++編譯器會先構造父類結構,之後再構造子類結構.而繼承過來的函式在構造父類的時候就確定了.其並不知道子類的成員變數,因此就無法訪問. 總之,這裡要注意,繼承過來的父類的成員函式(public, protected)在子類中可以使用,但是如果成員函式呼叫了成員變數,該成員變數也需要在子類中被繼承才行(如果成員變數在父類中是privated的就會有問題,子類中從新定義同名成員變數沒有任何作用也不可能有任何作用).對繼承來的父類的linkList,在子類中可以使用強制型別轉換.將其轉換為PriorityQueueLinkList. 這樣做是安全的,因為傳入的data本來必須要保證是優先順序佇列中的結點的資料結構.
((PriorityQueueLinkList<T, capacity>*)linkList)->enqueueWithPriority(data);
關鍵資料結構PriorityQueueLinkList,繼承自QueueLinkList. 重新寫enque方法.並利用C++的隱藏,將尾插入方法隱藏,因為優先順序佇列不適用尾插入暴露在外面. 出佇列方法則可以直接使用繼承自父類的dequeue.
該佇列插入的效率有一定問題,在佇列超過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;
}