循環隊列
當用順序結構實現隊列時如圖所示:可以用一個數組代表隊列空間,隊列為空時 rear和front都是指向數組第一個元素。
從隊尾插入的時候可以先將隊尾指向的數組賦值,再將隊尾指針+1
從對頭彈出元素則是先給取出元素值再將隊頭指針+1
但如果這么做,就會遇到一個棘手的問題,那就是隊頭彈出和隊尾插入都是讓各自指針+1,那么最終兩個指針都可能到達可索引數組的最大值導致數組越界,而這時棧空間可能是空的。例如下面的當插入最后一個元素e6之后,隊尾指針顯然已經越界了,這時已經不能插入,但棧的空間實際還有剩余。
解決的辦法是將順序隊列變成循環隊列。就是讓隊頭指針或隊尾指針在當越界的那一時刻重新指向數組的開始,從而形成一個環狀。可以想到的是用if語句來檢測到是否達頂端然后考慮是否將指針置向初始位置。如rear++; if(rear == MAXQSIZE) rear = 0;
。但用下面這個式子顯然更方便 rear = (rear+1) % MAXQSIZE;
當還沒到頂時對 MAXQSIZE 取余總的到rear+1,但是當rear+1到頂時則得到0,這個結果和if實現的功能一致,但更簡潔了。
完整示例代碼
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXQSIZE 100
typedef int Status;
typedef int QElemType;
typedef struct
{
QElemType * base; /* 指向動態分配的存儲空間 */
int front; /* 頭指針,若隊列不為空,指向隊列頭元素 */
int rear; /* 尾指針,若隊列不為空,指向隊列尾元素的下一個位置 */
}SqQueue;
/* 構造隊列 */
Status InitQueue(SqQueue *Q)
{
Q->base = (QElemType*)malloc(sizeof(QElemType));
if(!Q->base)
return ERROR;
Q->front = Q->rear = 0;
return OK;
}
/* 銷毀隊列 */
Status DestroyQueue(SqQueue *Q)
{
if(!Q->base)
return ERROR;
free(Q->base);
Q->base = NULL;
Q->front = Q->rear = 0;
return OK;
}
/* 清空隊列 */
Status ClearQueue(SqQueue *Q)
{
Q->front = Q->rear = 0;
return OK;
}
/* 判斷隊列是否為空 */
Status QueueEmpty(SqQueue *Q)
{
if(Q->front == Q->rear)
return TRUE;
else
return FALSE;
}
/* 返回隊列長度 */
int QueueLength(SqQueue *Q)
{
/* 如果front在上面,rear在下面,差為負號+MAXQSIZE剛好,括號結果小於MAXQSIZE
* 取余后為原值,當font在下面,括號超過MAXQSIZE,但是取余后只取小於那部分 */
return (Q->rear - Q->front + MAXQSIZE) % MAXQSIZE;
}
/* 獲取隊頭元素 */
Status GetHead(SqQueue *Q, QElemType *e)
{
if(!Q->base)
return ERROR; /* 隊列不存在 */
*e = Q->base[Q->front];
return OK;
}
/* 插入元素e到隊尾 */
Status EnQueue(SqQueue *Q, QElemType e)
{
if((Q->rear+1) % MAXQSIZE == Q->front)
return ERROR; /* rear剛好在front下面一個 隊列滿 */
Q->base[Q->rear] = e; /* 插入隊尾 */
Q->rear = (Q->rear+1) % MAXQSIZE; /* 隊尾+1,如果到頂取余后則又從底下開始了 */
return OK;
}
/* 從隊頭彈出元素 */
Status DeQueue(SqQueue *Q, QElemType *e)
{
if(Q->front == Q->rear)
return ERROR; /* 隊列空 */
*e = Q->base[Q->front]; /* 彈出元素 */
Q->front = (Q->front +1) % MAXQSIZE; /* 隊頭+1,若到頂,則從0開始 */
return OK;
}
/* 從隊頭到隊尾打印隊列 */
void printQueue(SqQueue *Q)
{
int p = Q->front;
while(p != Q->rear) { /* 還又元素沒打印 */
printf("%d ",Q->base[p]);
p = (p+1) % MAXQSIZE; /* p+1,若到頂,則從0開始 */
}
printf("\n");
}
int main()
{
SqQueue Queue;
SqQueue * Q = &Queue;
QElemType e;
InitQueue(Q);
EnQueue(Q,1);
EnQueue(Q,2);
EnQueue(Q,3);
EnQueue(Q,4);
printQueue(Q);
// 獲取長度測試
printf("len %d\n",QueueLength(Q));
// 是否為空測試
printf("empty? %d\n",QueueEmpty(Q));
// 獲取隊頭測試
GetHead(Q,&e);
printf("head? %d\n",e);
// 出隊列測試
DeQueue(Q,&e);
printf("e %d\n",e);
printQueue(Q);
// 清空隊列測試
ClearQueue(Q);
printQueue(Q);
// 銷毀隊列測試
DestroyQueue(Q);
return 0;
}