佇列---基本概念、順序佇列
一、基本概念
佇列(Queue)是隻允許在一端進行插入操作,而在另一端進行刪除操作的線性表。
佇列是一種先進先出(First In First Out)的線性表,簡稱FIFO。允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。
佇列基本操作:
InitQueue() ——初始化佇列
EnQueue() ——進佇列
DeQueue() ——出佇列
IsQueueEmpty() ——判斷佇列是否為空
IsQueueFull() ——判斷佇列是否已滿
佇列可以由陣列和連結串列兩種形式實現佇列操作。分別稱為順序佇列和鏈佇列。
順序佇列:順序儲存的佇列。
鏈佇列
二、順序佇列
我們一直都是用陣列來實現順序儲存的,順序佇列也不例外。所以我們可以定義一個數組int data[MAXSIZE]
來儲存佇列的元素。另外,我們還需要兩個指標,來標記隊頭和隊尾。
實現要點:
(1)順序佇列初始化:就是把隊頭和隊尾都歸0,也就是 Q->front=0; Q->rear=0;
每當插入新的佇列尾元素時,“尾指標增1”;每當刪除佇列頭元素時,“頭指標增1”。因此,非空佇列中,頭指標始終指向佇列頭元素,而尾指標始終指向佇列尾元素的下一位置。如圖:
(2)入隊的演算法應該怎麼寫?佇列是線性表,用陣列實現,因此首先要判斷佇列是不是滿的。
如何判斷一個佇列是否滿的?
假設我們在軍訓中排隊,每個人報數。一個佇列只能站10個人,從1報到10,隊就滿了。後來呢,隊頭的兩個人出隊了,然後又補充了兩個新隊員,那麼這時候的報數是3到12。這時佇列也是滿的。兩種情況下判斷隊滿的條件分別為:
(10 + 1) mod 10 = 1
(12 + 1) mod 10 = 3
所以佇列滿的條件就是 :
(Q->rear+1)%MAXSIZE == Q->front
(3)如果隊不滿,我們就可以入隊了。
思路就是,先給隊尾元素賦值,然後再將隊尾指標向後移動一位。
比如從空佇列開始,此時 Q->front == Q->rear,這個時候插入元素的話,其實就是給 data[Q->rear] 賦值 e;然後隊尾指標 Q->rear 向後移動一位重新賦值,使用
Q->rear = (Q->rear+1)%MAXSIZE;
即可完成尾指標後移。入隊操作:
/* 若佇列未滿,則插入元素e為Q新的隊尾元素 */
Status EnQueue(SqQueue *Q,QElemType e)
{
if ((Q->rear+1)%MAXSIZE == Q->front) /* 佇列滿的判斷 */
return ERROR;
Q->data[Q->rear]=e; /* 將元素e賦值給隊尾 */
Q->rear=(Q->rear+1)%MAXSIZE;/* rear指標向後移一位置, */
/* 若到最後則轉到陣列頭部 */
return OK;
}
(4)出隊操作 。
首先,佇列空的判斷依據:Q->front == Q->rear
只要將隊頭指標向後移動一位就可以完成出隊 Q->front=(Q->front+1)%MAXSIZE;
在這之前需要用 e 來儲存出隊的元素。出隊函式如下:
/* 若佇列不空,則刪除Q中隊頭元素,用e返回其值 */
Status DeQueue(SqQueue *Q, QElemType *e)
{
if (Q->front == Q->rear) /* 佇列空的判斷 */
return ERROR;
*e=Q->data[Q->front]; /* 將隊頭元素賦值給e */
Q->front=(Q->front+1)%MAXSIZE; /* front指標向後移一位置, */
/* 若到最後則轉到陣列頭部 */
return OK;
}
(5)置空順序佇列。只要讓隊頭指標與隊尾指標相等即可。
/* 將Q清為空佇列 */
Status ClearQueue(SqQueue *Q)
{
Q->front=Q->rear=0;
return OK;
}
(6)獲取佇列長度。可以使用模運算來獲取佇列的長度。具體演算法:隊尾指標 - 隊頭指標 + 陣列長度的和再模陣列長度即可。
/* 返回Q的元素個數,也就是佇列的當前長度 */
int QueueLength(SqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
順序佇列實現程式碼如下:
#include <iostream>
using namespace std;
#define maxsize 20 /* 儲存空間初始分配量 */
typedef int QElemType;
//迴圈佇列順序儲存結構
typedef struct
{
QElemType a[maxsize];
int front;//佇列頭指標
int rear;//佇列尾指標,若佇列不空,指向佇列尾元素的下一個位置
}SqQueue;
//佇列初始化函式
void InitQueue(SqQueue *q)
{
q->front = q->rear = 0;
}
//判斷佇列是否為空
bool IsEmpty(SqQueue *q)
{
return q->front == q->rear;
}
//判斷佇列是否已滿
bool IsFull(SqQueue *q)
{
return (q->rear + 1)%maxsize == q->front;
}
//獲取佇列長度
void QueueLength(SqQueue *q)
{
int length = (q->rear - q->front + maxsize) % maxsize;
cout<<"佇列長度:"<<length<<endl;
}
//入隊
void EnQueue(SqQueue *q, QElemType x)
{
if(IsFull(q))
{
cout<<"佇列已滿!"<<endl;
}
else
{
q->a[q->rear] = x;//先把入隊值賦給隊尾指標指向的地方(原佇列隊尾的下一位置)
q->rear = (q->rear+1)%maxsize;//隊尾指標後移
}
}
//出隊
void DeQueue(SqQueue *q)
{
QElemType x;
if(IsEmpty(q))
{
cout<<"佇列已空!"<<endl;
}
else
{
x = q->a[q->front];
cout<<"delete x="<<x<<endl;
q->front = (q->front+1)%maxsize;
}
}
//將佇列清空
void ClearQueue(SqQueue *q)
{
cout<<"請空佇列!"<<endl;
q->front = q->rear = 0;
}
//列印佇列
void PrintQueue(SqQueue *q)
{
if(IsEmpty(q))
{
cout<<"佇列為空,無法輸出!"<<endl;
}
for(int i=q->front; i%maxsize < q->rear; i++)
{//q->rear指向尾元素的下一位置!!!
if(i == q->rear-1)
{//遍歷到尾元素
cout<<q->a[i]<<endl;
}
else
{
cout<<q->a[i]<<" ";
}
}
}
int main()
{
SqQueue *q;
InitQueue(q);
EnQueue(q, 1);
PrintQueue(q);
EnQueue(q, 2);
PrintQueue(q);
EnQueue(q, 3);
PrintQueue(q);
EnQueue(q, 4);
PrintQueue(q);
QueueLength(q);
DeQueue(q);
PrintQueue(q);
DeQueue(q);
PrintQueue(q);
QueueLength(q);
ClearQueue(q);
QueueLength(q);
PrintQueue(q);
return 0;
}
結果:
1
1 2
1 2 3
1 2 3 4
佇列長度:4
delete x=1
2 3 4
delete x=2
3 4
佇列長度:2
請空佇列!
佇列長度:0
佇列為空,無法輸出!
Process returned 0 (0x0) execution time : 5.301 s
Press any key to continue.