1,綜述
/********************************************************/
// 用模板實現隊列(Queue)的基類定義
// 隊列,先進先出(FIFO)的線性表
/********************************************************/
#pragma once
#include "Public.h"
template<class E>
class Queue
{
public:
Queue() {}
virtual ~Queue() {}
virtual void clear() = 0;
// 入隊,只能從隊尾插入
virtual void enqueue(const E& it) = 0;
// 出隊,只能從隊首刪除,返回類型不能是引用,因爲返回的隊首值已經不存在了
virtual E dequeue() = 0;
// 返回隊首的值,返回類型是const引用,所以你能獲取值,但不能改變它
virtual const E& frontValue()const = 0;
// 返回棧中當前存儲的元素個數
virtual int length() const = 0;
};
2,順序隊列(array based queue)
用數組模擬隊列,首先想到的,就是把隊首放在a[0]位置,剩下的依次排放,新元素入隊就放在後面排隊,出隊的時候,就必須後面所有的元素都往前移一位,就好像我們排隊的時候,最前面的人走了,後面所有人必須都往前走一步,隊伍才能前進一樣。但是這樣會耗費態度的資源。所以將其改進爲不強制要求隊首必須在a[0],只要能知道隊首所在的數組下標即可。但是這樣一來,一旦發生出隊,a[0]和隊首之間的內存就被浪費了,永遠都沒辦法利用。改進的方案是,當如隊到達數組的最後一個位置a[len-1]後,開始向a[0]填充元素,但不能越過隊首。這樣一來,直線的排列方式實際上已經變成圓環形了。/********************************************************/
// 用數組實現順序隊列(array based queue)的定義
// 繼承基類棧 Queue<E>
/********************************************************/
#pragma once
#include "Queue.h"
const size_t defaultQSize = 5;//Queue數據的默認長度
template<class E>
class AQueue : public Queue<E>
{
private:
E* data; //存儲Queue數據的數組
int front; //隊首的數組下標
int rear; //隊尾的數組下標+1
int maxSize;//簡單實現,只開闢一次空間,所以有最大大小
int iNr; //隊列中的元素個數,隊列長度
public:
AQueue(size_t size = defaultQSize);
~AQueue();
void clear();
// 入隊,只能從隊尾插入
void enqueue(const E& it);
// 出隊,只能從隊首刪除,返回類型不能是引用,因爲返回的隊首值已經不存在了
E dequeue();
// 返回類型是const引用,所以你能獲取棧頂的值,但不能改變它
const E& frontValue()const;
// 返回棧中當前存儲的元素個數
int length() const;
};
ArrayQueue_Def.h:
/********************************************************/
// 用數組實現順序隊列(array based queue)的定義
// 繼承基類棧 Queue<E>
// 此處實現AQueue<E>的成員函數
/********************************************************/
#pragma once
#include "ArrayQueue.h"
// 定義構造函數,開闢空間
template<class E>
AQueue<E>::AQueue(size_t size = defaultSize) : front(0), rear(0),iNr(0),maxSize(size)
{
data = new E[size];
}
template<class E>
AQueue<E>::~AQueue()
{
delete[] data;
}
// 清空棧,只是修改top下標,不收回內存
template<class E>
void AQueue<E>::clear()
{
front = rear = iNr = 0;
}
// 入隊,只能從隊尾插入
template<class E>
void AQueue<E> ::enqueue(const E& it)
{
Assert(iNr < maxSize, "隊列已滿");
// 小於maxSize時就是rear,等於maxSize時變成0
rear %= maxSize;
data[rear++] = it;
iNr++;
}
// 彈出棧頂元素
template<class E>
E AQueue<E> ::dequeue()
{
Assert(iNr > 0, "空隊列");
E it = data[front++]; //front下移一位
front %= maxSize; // 小於maxSize時就是front,等於maxSize時變成0
iNr--;
return it;
}
// 獲取棧頂元素
template<class E>
const E& AQueue<E> ::frontValue() const
{
Assert(iNr > 0, "空棧");
return data[front];
}
// 返回棧中元素個數
template<class E>
int AQueue<E>::length() const
{
return iNr;
}
3,鏈式隊列
/********************************************************/
// 用模板實現鏈式隊列(Linked Queue)的定義
// 是單向鏈表的簡化
// 繼承基類 Queue<E>
/********************************************************/
#pragma once
#include "Queue.h"
// 1,定義節點類模板
template<class E>
class QNode
{
public:
E element; //本結點存儲的元素值
QNode* next;//指向下一結點的指針
QNode(const E& elemval, QNode* nextval = NULL) :element(elemval), next(nextval) {}
QNode(QNode* nextval = NULL) :next(nextval) {}
};
// 2,定義鏈表類模板
template<class E>
class LQueue : public Queue<E>
{
private:
QNode<E>* front; //隊首
QNode<E>* rear; //隊尾
int cnt; //鏈表中當前存儲的元素個數
void init(); //初始化
public:
LQueue();
~LQueue();
void print() const;
void clear();
// 入隊,只能從隊尾插入
void enqueue(const E& it);
// 出隊,只能從隊首刪除,返回類型不能是引用,因爲返回的隊首值已經不存在了
E dequeue();
// 返回棧中當前存儲的元素個數
int length() const;
// 返回隊首的值,返回類型是const引用,所以你能獲取值,但不能改變它
const E& frontValue()const;
};
LinkedQueue_Def.h:
/********************************************************/
// 用模板實現鏈式隊列(Linked Queue)的定義
// 是單向鏈表的簡化
// 繼承基類 Queue<E>
// 本文件實現成員函數的定義
/********************************************************/
#pragma once
#include "LinkedQueue.h"
template<class E>
void LQueue<E>::init()
{
//所有指針指向新開的空間
front = rear = new QNode<E>();
cnt = 0;
}
//構造函數
template<class E>
LQueue<E>::LQueue()
{
//構造時只開闢一個節點的空間
init();
}
//析構函數
template<class E>
LQueue<E>::~LQueue()
{
clear();
delete front; //空的首節點也不能留
}
//打印所有元素
template<class E>
void LQueue<E>::print() const
{
Node<E>* temp = front->next; //head中不存儲數據,head->next中才有數據
while (NULL != temp)
{
//此處暗示類型E必須定義了“<<”操作,否則報錯
cout << temp->element << endl;
temp = temp->next;
}
}
//清空鏈表
template<class E>
void LQueue<E>::clear()
{
QNode<E>* temp = front->next;
//刪除除front之外的所有節點
while(NULL != temp)
{
front->next = temp->next;
delete temp;
temp = front->next;
}
rear = front;
cnt = 0;
}
//入隊
template<class E>
void LQueue<E>::enqueue(const E& it)
{
rear = rear->next = new QNode<E>(it);
cnt++;
}
//出隊
template<class E>
E LQueue<E>::dequeue()
{
// 由於front節點不存儲真實的內容,要刪除的不是front,而是front->next
Assert(cnt != 0, "隊列爲空");
QNode<E>* temp = front->next;
E it = front->next->element;
// front節點的位置不變,但是front->next指向下一個
front->next = temp->next;
// 要刪除的是最後一個元素
if (temp == rear)
{
rear = front;
}
delete temp;
cnt--;
return it;
}
// 返回個數
template<class E>
int LQueue<E>::length() const
{
return cnt;
}
template<class E>
const E& LQueue<E>::frontValue()const
{
return front->next->element;
}