複製鏈接
請複製以下鏈接發送給好友

循環隊列

鎖定
為充分利用向量空間,克服"假溢出"現象的方法是:將向量空間想象為一個首尾相接的圓環,並稱這種向量為循環向量。存儲在其中的隊列稱為循環隊列(Circular Queue)。循環隊列是把順序隊列首尾相連,把存儲隊列元素的表從邏輯上看成一個環,成為循環隊列。
中文名
循環隊列
外文名
Circular Queue
領    域
數據結構
實現方式
單鏈表
有關術語
隊列
特    點
大小固定

循環隊列簡介

循環隊列就是將隊列存儲空間的最後一個位置繞到第一個位置,形成邏輯上的環狀空間,供隊列循環使用。在循環隊列結構中,當存儲空間的最後一個位置已被使用而再要進入隊運算時,只需要存儲空間的第一個位置空閒,便可將元素加入到第一個位置,即將存儲空間的第一個位置作為隊尾。 [1]  循環隊列可以更簡單防止偽溢出的發生,但隊列大小是固定的。
在循環隊列中,當隊列為空時,有front=rear,而當所有隊列空間全佔滿時,也有front=rear。為了區別這兩種情況,規定循環隊列最多隻能有MaxSize-1個隊列元素,當循環隊列中只剩下一個空存儲單元時,隊列就已經滿了。因此,隊列判空的條件是front=rear,而隊列判滿的條件是front=(rear+1)%MaxSize。 [2] 

循環隊列基本操作

// 隊列的順序存儲結構(循環隊列)
#define MAX_QSIZE 5 // 最大隊列長度+1
typedef struct {
    int *base; // 初始化的動態分配存儲空間
    int front; // 頭指針,若隊列不空,指向隊列頭元素
    int rear; // 尾指針,若隊列不空,指向隊列尾元素的下一個位置
} SqQueue;


// 構造一個空隊列Q
SqQueue* Q_Init() {
    SqQueue *Q = (SqQueue*)malloc(sizeof(SqQueue));
    // 存儲分配失敗
    if (!Q){
        exit(OVERFLOW);
    }
    Q->base = (int *)malloc(MAX_QSIZE * sizeof(int));
    // 存儲分配失敗
    if (!Q->base){
        exit(OVERFLOW);
    }
    Q->front = Q->rear = 0;
    return Q;
}

// 銷燬隊列Q,Q不再存在
void Q_Destroy(SqQueue *Q) {
    if (Q->base)
        free(Q->base);
    Q->base = NULL;
    Q->front = Q->rear = 0;
    free(Q);
}

// 將Q清為空隊列
void Q_Clear(SqQueue *Q) {
    Q->front = Q->rear = 0;
}

// 若隊列Q為空隊列,則返回1;否則返回-1
int Q_Empty(SqQueue Q) {
    if (Q.front == Q.rear) // 隊列空的標誌
        return 1;
    else
        return -1;
}

// 返回Q的元素個數,即隊列的長度
int Q_Length(SqQueue Q) {
    return (Q.rear - Q.front + MAX_QSIZE) % MAX_QSIZE;
}

// 若隊列不空,則用e返回Q的隊頭元素,並返回OK;否則返回ERROR
int Q_GetHead(SqQueue Q, int &e) {
    if (Q.front == Q.rear) // 隊列空
        return -1;
    e = Q.base[Q.front];
    return 1;
}

// 打印隊列中的內容
void Q_Print(SqQueue Q) {
    int p = Q.front;
    while (Q.rear != p) {
        cout << Q.base[p] << endl;
        p = (p + 1) % MAX_QSIZE;
    }
}

// 插入元素e為Q的新的隊尾元素
int Q_Put(SqQueue *Q, int e) {
    if ((Q->rear + 1) % MAX_QSIZE == Q->front) // 隊列滿
        return -1;
    Q->base[Q->rear] = e;
    Q->rear = (Q->rear + 1) % MAX_QSIZE;
    return 1;
}

// 若隊列不空,則刪除Q的隊頭元素,用e返回其值,並返回1;否則返回-1
int Q_Poll(SqQueue *Q, int &e) {
    if (Q->front == Q->rear) // 隊列空
        return -1;
    e = Q->base[Q->front];
    Q->front = (Q->front + 1) % MAX_QSIZE;
    return 1;
}

循環隊列條件處理

循環隊列中,由於入隊時尾指針向前追趕頭指針;出隊時頭指針向前追趕尾指針,造成隊空和隊滿時頭尾指針均相等。因此,無法通過條件front==rear來判別隊列是"空"還是"滿"。
解決這個問題的方法至少有兩種:
① 另設一布爾變量以區別隊列的空和滿;
②另一種方式就是數據結構常用的: 隊滿時:(rear+1)%n==front,n為隊列長度(所用數組大小),由於rear,front均為所用空間的指針,循環只是邏輯上的循環,所以需要求餘運算。如圖1所示情況,隊已滿,但是rear(5)+1=6!=front(0),對空間長度求餘,作用就在此6%6=0=front(0)。
圖1 圖1
類型定義採用環狀模型來實現隊列,各數據成員的意義如下:
front指定隊首位置,刪除一個元素就將front順時針移動一位;
rear指向元素要插入的位置,插入一個元素就將rear順時針移動一位;
count存放隊列中元素的個數,當count等於MaxQSize時,不可再向隊列中插入元素。

循環隊列隊列

數據結構分為線性結構和非線性結構,隊列和線性表都是線性結構。線性表是由n 個數據元素組成的有限序列,該序列有惟一的“第一個”和惟一的“最後一個”數據元素;除了 “第一個”和“最後一個”之外,隊列中的每個數據元素都只有一個直接前驅和一個直接後繼。線性表的插入和刪除操作可以在表中任意位置進行。隊列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作,和一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。隊列中沒有元素時,稱為空隊列。
隊列的數據元素又稱為隊列元素。在隊列中插入一個隊列元素稱為入隊,從隊列中刪除一個隊列元素稱為出隊。因為隊列只允許在一端插入,在另一端刪除,所以只有最早進入隊列的元素才能最先從隊列中刪除,故隊列又稱為先進先出(FIFO—first in first out)線性表。
參考資料