數據結構-隊列

隊列即先進先出(FIFO)的線性表。怎麼來比喻隊列呢?相當於有一排座位,只能依次從右邊入座,從左邊離開。入座的時候,第一個人坐最左邊,第二個人坐左邊的第二個位置,依次類推;出場的時候,最左邊的人先走。

 

1. 循環(順序)隊列

       普通順序隊列有一個問題,假如中場的時候,最左邊走了幾個人,那麼此時最左邊的人,坐的卻不是最左邊的座位,因爲最左邊的人走後,頭指針就移動到了此時最左邊的人身上(而人無需移動),所以那些空位置就再也用不上了,造成了“假上溢”。所以普通順序隊列沒意思,循環隊列纔可行。

       注意:自始至終,這些座位都是編好號的,從左到右依次爲0,1,2,…類似於數組,座位的總個數即MAXSIZE,但是隻能坐MAXSIZE-1個人,隊頭和隊尾之間要留一個空位,即sq->rear+1=MAXSIZE時就意味着坐滿了。

       循環隊列的關鍵算法是,判斷隊尾是否還有空座,如果沒有了,就再看看最左邊是否有人離開而騰出來的空座位,如果左邊頭上有人,證明頭尾都坐滿了人,如果左邊有空位,說明已經有人離開了,後來的人就直接坐到左邊去。即:

if( sq->rear+1>= MAXSIZE )

       sq->rear=0; //坐不下了,轉到隊頭去,看看隊頭有沒有人。

else

       sq->rear++; //坐得下,直接坐到後面

將上面兩句改成如下形式:

sq->rear =(sq->rear+1)%MAXSIZE;

       二者等價。實際上,sq->rear+1不會大於MAXSIZE,最多等於MAXSIZE,所以說上面那個if正確的寫法應該是if( sq->rear+1==MAXSIZE ),如果sq->rear+1= MAXSIZE,則sq->rear就等於0,否則sq->rear=餘數= sq->rear+1,所以說if else和求模運算是等價的。

 

循環隊列的數據結構如下

typedef struct

{

       DataType data[QueueSize];

       int front;//頭指針

       int rear;//尾指針    

}CirQueue;  

 

其他操作如下:

// 置隊列空

void Initial(CirQueue *Q)

{

       Q->front=Q->rear=QueueSize-1;//注意這個絕對不能寫作-1等,寫成0也可以

}

 

// 判隊列空

int IsEmpty(CirQueue *Q)

{

       return Q->front==Q->rear;

}

 

//判隊列滿

int IsFull(CirQueue *Q)

{

       return (Q->rear+1)%QueueSize==Q->front;//這句很多地方都要用到

}

 

//入隊

void EnQueue(CirQueue *Q,DataType x)

{

       /*關鍵算法:新元素存入隊尾,隊尾再後移一位*/

       Q->data[Q->rear]=x;                 //新元素插入隊尾

       Q->rear=(Q->rear+1)%QueueSize;      //循環意義下將尾指針加1

}

 

//出隊

void DeQueue(CirQueue *Q)

{

       /*關鍵算法:最左邊的人走後,就將隊頭front往右移一位(即循環意義下+1)*/

       Q->front=(Q->front+1)%QueueSize;   //循環意義下的頭指針加1

}

 

2. 鏈隊列

數據結構如下:

typedef struct node{

       DataType data;

       struct node *next;

}LinkQueue;

typedef struct{

       LinkQueue *front;  //頭指針

       LinkQueue *rear;

}QueueNode;

同樣(見上一篇文章"棧"),關於QueueNode我們也可以用數組LinkQueue *QueueNode[2]來實現。

 

基本操作

// 置隊列空

void Initial(QueueNode *Q)

{

    Q->front=Q->rear=NULL;

}

//判隊列空

int IsEmpty(QueueNode *Q)

{

    return Q->front==NULL&&Q->rear==NULL;

}

//進隊列

void Push(QueueNode *Q,DataType x)

{//將元素x插入鏈隊列尾部

       LinkQueue *p=(LinkQueue *)malloc(sizeof(LinkQueue));//申請新結點

       p->data=x;

       p->next=NULL;

    if(IsEmpty(Q))

              Q->front=Q->rear=p;  //將x插入空隊列

       else

       {

              Q->rear->next=p; //(Q->rear)是隊尾的指針,即:使隊尾結構體的next指針指向p

              Q->rear=p;     //隊尾指針指向新的尾

       }

}

//出隊列

DataType Pop(QueueNode *Q)

{

       LinkQueue *p;

       p=Q->front;                   //保存隊頭結點

       Q->front=p->next;             //使隊頭指向p後面的一位

    if(Q->rear==p)//原隊中只有一個結點的情況,刪去後隊列變空,所以尾指針也應置空

              Q->rear=NULL;

       free(p);   //釋放被刪隊頭結點

}

 

注意上面列出的只是算法的關鍵部分,並不完整,刪減了一些無礙算法邏輯的內容。

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