數據結構與算法——循環隊列

  今天總結循環隊列。

什麼是隊列?

   隊列跟棧差不多,也是一種操作受限的線性表,只允許在線性表的一端進行插入操作,在另一端進行刪除操作。插入的一端稱爲隊尾,刪除的一端稱爲隊頭,插入操作稱爲入隊,而刪除操作稱作出出隊,不含任何數據元素的隊稱爲空隊。隊列也有兩種實現方式,一種就是順序存儲,用數組實現,另一種是採用鏈表形式。今天總結順序存儲的循環隊列。

什麼是循環隊列?

   循環隊列就是,當隊尾指針移動到數組末尾時,下次再有元素入隊時,可以將隊尾指針重新移到數組前面沒有元素的位置。

爲什麼要使用循環隊列?

   循環隊列解決了,數組空間利用率的問題。設想,如果每將一個隊列出隊,則將後面的元素都向前移動,那麼這個時候的時間複雜度爲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>


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章