1. 程式人生 > >佇列---基本概念、順序佇列

佇列---基本概念、順序佇列

一、基本概念

佇列(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.