今天總結循環隊列。
什麼是隊列?
隊列跟棧差不多,也是一種操作受限的線性表,只允許在線性表的一端進行插入操作,在另一端進行刪除操作。插入的一端稱爲隊尾,刪除的一端稱爲隊頭,插入操作稱爲入隊,而刪除操作稱作出出隊,不含任何數據元素的隊稱爲空隊。隊列也有兩種實現方式,一種就是順序存儲,用數組實現,另一種是採用鏈表形式。今天總結順序存儲的循環隊列。
什麼是循環隊列?
循環隊列就是,當隊尾指針移動到數組末尾時,下次再有元素入隊時,可以將隊尾指針重新移到數組前面沒有元素的位置。
爲什麼要使用循環隊列?
循環隊列解決了,數組空間利用率的問題。設想,如果每將一個隊列出隊,則將後面的元素都向前移動,那麼這個時候的時間複雜度爲O(n),但是如果出隊時,我們只將隊頭指針移向下一位,這樣時間複雜度就爲O(1),只是當隊頭指不斷後移時,出隊元素佔用的空間就不能用了,這樣隊列的可用空間越來越少,當隊尾指針到達數組末尾時,再插入元素就不行了,而此時出隊的空間其實是可以放入元素的,因此我們就採用循環方式,讓隊尾指針可以移向前面出隊元素的位置,並將元素插入。
隊列中存在兩個指針,一個時隊頭指針,一個時隊尾指針,當隊列爲空時,則隊頭與隊尾指針相等,均指向數組中的0下標。在隊列中,隊頭所指的元素是不存在隊列中,也就是說隊頭後面的那個元素纔是隊列的頭元素。當隊頭與隊尾指向同一處時(除過數組下標0這個位置),則隊已滿。
入隊:當隊列不滿時,則將隊尾指針向後移一位,將元素插入到這個位置。
獲取隊長度:有兩種方法。
- 用rear-front即可得出,但因爲是循環隊列,所有,有可能rear位置在front前面。當rear在前面時,則QueueSize-(QueueSize-rear-(QueueSize-front))= rear-front+QueueSize
將兩種情況合並可以這樣寫 (rear-front+QueueSize)%QueueSize - 初始化一計數器count,從隊頭指針開始移動,當rear!=front 就一直循環,計數器不斷增1,直到rear==front
<span style="font-family:Courier New;font-size:14px;">#include <iostream>
using namespace std;
const int QueueSize = 10;
template <class T>
class CircleQueue {
public:
CircleQueue() {
front = rear = 0; //空隊列
}
void EnQueue(T x); //入隊操作
T DeQueue(); //出隊操作
T GetFront(); //查找對頭元素
bool IsEmpty() { //判空隊列
return rear==front?true:false;
}
int GetLength(); //隊列長度
void PrintQueue(); //遍歷隊列
private:
T data[QueueSize];
int front; //隊頭指針
int rear; //隊尾指針
};
template <class T>
void CircleQueue<T>::EnQueue(T x) {
if((rear+1)%QueueSize==front)
throw "隊列爲空";
rear = (rear+1)%QueueSize; //隊尾指針後移
data[rear] = x;
}
template <class T>
T CircleQueue<T>::DeQueue() {
if(rear==front)
throw "隊列爲空";
front = (front+1)%QueueSize;
return data[front];
}
template <class T>
int CircleQueue<T>::GetLength() {
int count = 0;
int p = front;
while(rear!=front) {
count++;
front = (front+1)%QueueSize;
}
front = p;
return count;
//第二種獲取隊列長度的方法 這裏要分兩種請框 rear>front
//和rear<front 合併後就爲下面這個 可以仔細推一下
// return (rear-front+QueeuSize)%QueueSize;
}
template <class T>
T CircleQueue<T>::GetFront() {
if(front==rear)
throw "隊列爲空";
return data[(front+1)%QueueSize];
}
template <class T>
void CircleQueue<T>::PrintQueue() {
int p = front; //保留頭指針
while(front!=rear) {
cout<<data[(front+1)%QueueSize]<<" ";
front = (front+1)%QueueSize; //移動頭指針
}
front = p; //隊頭指針歸位
cout<<endl;
}
int main()
{
CircleQueue<int> circleQueue;
for(int i=0;i<9;i++) {
circleQueue.EnQueue(i);
}
cout<<"隊列長度"<<endl;
cout<<circleQueue.GetLength()<<endl;;
cout<<"遍歷隊列"<<endl;
circleQueue.PrintQueue();
//出隊
circleQueue.DeQueue();
circleQueue.DeQueue();
circleQueue.EnQueue(7);
circleQueue.EnQueue(11);
cout<<"遍歷隊列"<<endl;
circleQueue.PrintQueue();
cout<<"獲取隊頭元素"<<endl;
cout<<circleQueue.GetFront()<<endl;
return 0;
}</span>