資料結構——迴圈佇列(順序佇列)模板類實現
阿新 • • 發佈:2019-01-10
資料結構筆記3.3
順序佇列是用順序表實現的(即依託於陣列),這裡實現的是迴圈佇列,其實也可以不用迴圈,但是那樣的話,空間的利用效率就太低了,這就是”假溢位”問題,因為在陣列的前端可能還有空閒的位置(因為佇列中的資料是在動態變化的,可能出隊也可能入對)。
為了能夠充分利空間,所以用迴圈佇列,即在邏輯上把陣列的隊結構看成一個環。具體實現:實現的方式還是十分巧妙地,運用兩個指標和鍾運算(就是取模或是取餘運算)。
隊頭指標進1:front = (front + 1) % maxSize;
隊尾指標進1 : rear = (rear + 1) % maxSize;
上面兩個式子就是鍾運算在佇列資料操作時候的實現原理。
另外,在判斷佇列NULL與佇列FULL的時候會遇到混淆的問題,NULL的時候,在即rear == front ,但是由於是迴圈表,當表FULL的時候,兩者也是相等的,一種區分方式就是當rear檢測到其下一個就是front的時候作為佇列滿的依據,這樣就相當於佇列滿的時候也會有一個節點是空閒的。
好了,在編寫這個類的過程中,需要強調的就這幾個地方,下面貼出程式碼:
虛基類程式碼(此程式碼段放入queue.h當中,並在模板類程式碼中包含)
template<class T>
class Queue {
public:
Queue(){} //建構函式
~Queue(){} //解構函式
virtual bool EnQueue(const T & x) = 0; //新元素x進入佇列
virtual bool DelQueue(T & x) = 0; //隊頭元素出佇列
virtual bool getFront(T & x) = 0; //讀取隊頭元素的值
virtual bool IsEmpty()const = 0; //判斷佇列是否為NULL
virtual bool IsFull() const = 0; //判斷佇列是否已滿
virtual int getSize() const = 0; //求佇列元素的個數
};
模板class程式碼:
#include <iostream>
#include <cassert>
#include <cmath>
#include "queue.h"
using namespace std;
//順序佇列模板類定義(迴圈佇列)
template<class T>
class SeqQueue : public Queue<T> {
public:
SeqQueue(int sz = 10); //建構函式
~SeqQueue(); //解構函式
//若佇列不滿則將x進入佇列,否則溢位處理
bool EnQueue(const T & x);
//若佇列不空則刪除隊頭元素x,並返回true,否則返回false
bool DelQueue(T & x);
//若佇列不空則函式返回隊頭元素並返回true,否則返回false
bool getFront(T & x);
//置空操作,隊頭指標與隊尾指標置0
void makeEmpty();
//判斷佇列是否為空,是則返回true否則返回false
bool IsEmpty() const;
//判斷佇列是否已滿,是返回true否則返回false
bool IsFull() const;
//求佇列元素的個數
int getSize() const;
//輸出佇列元素,運算子過載函式呼叫
void output(ostream & out);
protected:
int rear, front; //隊尾與隊頭指標
T *elements; //存放佇列元素的陣列
int maxSize; //佇列最大可容納的元素個數
};
//函式定義
template<class T>
SeqQueue<T>::SeqQueue(int sz) {
//建立一個最大就有maxSzie個元素的空佇列
maxSize = sz;
elements = new T[sz]; //開闢記憶體
assert(elements != NULL); //記憶體分配不成功的中斷處理
rear = front = 0; //初始化隊頭與隊尾指
}
template<class T>
SeqQueue<T>::~SeqQueue() {
//解構函式,釋放程式中相應的資源
delete[] elements;
}
template<class T>
bool SeqQueue<T>::EnQueue(const T & x) {
//若佇列不滿則將x進入佇列,否則溢位處理
if (IsFull()) {
//如果佇列已經滿,則返回false
return false;
}
elements[rear] = x;
rear = (rear + 1) % maxSize; //通過鍾運算實現元素的迴圈填充
return true;
}
template<class T>
bool SeqQueue<T>::DelQueue(T & x) {
//若佇列不空則刪除隊頭元素x,並返回true,否則返回false
if (IsEmpty()) {
return false;
}
x = elements[front];
front = (front + 1) % maxSize;
return true;
}
template<class T>
bool SeqQueue<T>::getFront(T & x) {
//若佇列不空則函式返回隊頭元素並返回true,否則返回false
if (IsEmpty()) {
return false;
}
x = elements[front];
return true;
}
template<class T>
bool SeqQueue<T>::IsEmpty() const {
if (rear == front) {
return true;
}
else {
return false;
}
}
template<class T>
bool SeqQueue<T>::IsFull() const {
if (fmod((rear + 1), maxSize) == front) {
//如果rear的下一個節點與front相同則定義為佇列已滿
//從而區分佇列為NULL,即rear==front的情況
return true;
//注意這個時候佇列中會有一個NULL的節點
}
else {
return false;
}
}
template<class T>
void SeqQueue<T>::makeEmpty() {
//置NULL操作
rear = front = 0;
}
template<class T>
int SeqQueue<T>::getSize() const {
//求佇列元素的個數
return (rear - front + maxSize) % maxSize;
}
template<class T>
void SeqQueue<T>::output(ostream & out) {
for (int i = front; i != rear; i = (i + 1) % maxSize) {
out << elements[i] << ' ';
}
cout << endl;
}
template<class T>
ostream & operator << (ostream & out, SeqQueue<T> & SQ) {
//過載插入運算子
SQ.output(out);
return out;
}
Main測試程式碼:
int main()
{
SeqQueue<int> squeue; //定義迴圈佇列物件
squeue.EnQueue(1); //進隊與出隊測試
squeue.EnQueue(2);
squeue.EnQueue(3);
squeue.EnQueue(4);
squeue.EnQueue(5);
cout << squeue;
int outQueVal_1, outQueVal_2;
squeue.DelQueue(outQueVal_1);
squeue.DelQueue(outQueVal_2);
cout << squeue;
int quFrontVal = 0;
squeue.getFront(quFrontVal); //提取隊頭資料測試
cout << quFrontVal << endl;
squeue.makeEmpty(); //設定NULL與測試NULL測試
if (squeue.IsEmpty()) {
cout << "佇列為NULL" << endl;
}
else {
cout << "佇列非空" << endl;
}
squeue.EnQueue(2); //取佇列大小測試
squeue.EnQueue(3);
squeue.EnQueue(4);
cout << squeue.getSize() << endl;
system("pause");
return 0;
}
執行結果: