隊列(Queue
)是具有一定操作約束的線性表。與堆棧有點類似,但是插入和刪除操作:只能在一端插入,而在另一端刪除。由於是單項鍊表,所以末端無法進行刪除操作。主要操作有兩種:
- 數據插入:入隊列(
AddQ
) - 數據刪除:出隊列(
DeleteQ
)
隊列滿足先來先服務,先進先出:FIFO
。
抽象數據類型描述
隊列的抽象數據類型描述如下所示:
類型名稱:隊列(Queue
)
數據對象集:一個有0個或多個元素的有窮線性表。
操作集:長度爲MaxSize
的隊列,隊列元素;
1、Queue CreatQueue( int MaxSize )
:生成長度爲MaxSize
的空隊列;
2、int IsFullQ( Queue Q, int MaxSize )
:判斷隊列Q
是否已滿;
3、void AddQ( Queue Q, ElementType item )
:將數據元素item
插入隊列Q
中;
4、int IsEmptyQ( Queue Q)
:判斷隊列Q
是否爲空;
5、ElementType DeleteQ( Queue Q)
:將隊頭數據元素從隊列中刪除並返回。
隊列的順序存儲結構通常由一個一維數組和一個記錄隊列頭元素位置的變量front
以及一個記錄隊列尾元素位置的變量rear
組成。
#define MaxSize <儲存數據元素的最大個數>
typedef struct {
ElementType Data[MaxSize];
int rear; ;
int front;
} Queue;
一個工作隊列入一個列表,如下圖所示:
添加的時候從右邊往裏面添加,出隊的時候從左邊取出。但是這種方式容易造成內存的浪費,比如Job 1
取出來之後,還有Job
想加入就無法從右邊加入,會發生衝突。因此有了順環隊列:
那這種方案,堆棧空和滿的判別條件是什麼?
其實就是Tail
指針和Head
指針指向同一處。而這種指向同一處的情況當空和滿是一樣的。對於這種情況可以設置Size記錄數據大小加以區分;或者判斷tag是0還是1來判斷最後一次是否是刪除操作來判斷空、滿;或者直接就設置個數組,使得整個隊列不會被放滿。
程序描述
入出隊
void AddQ( Queue *PtrQ, ElementType item)
{
if ( (PtrQ->rear+1) % MaxSize == PtrQ->front ) {
printf(“滿");
return
PtrQ->rear = (PtrQ->rear+1 )% MaxSize;
PtrQ->Data[PtrQ->rear] = item;
}
上述的Front
和rearl
指針的移動採用“加1取餘”法,體現了順序存儲的“循環使用”。
ElementType DeleteQ ( Queue *PtrQ )
{
if ( PtrQ->front == PtrQ->rear) {
printf(“隊列空");
return ERROR;
} else {
PtrQ->front = (PtrQ->front+1)% MaxSize;
return PtrQ->Data[PtrQ->front];
}
}
鏈式存儲
隊列的鏈式存儲結構也可以用一個單鏈表
實現。插入和刪除操作分別在鏈表的兩頭進行;隊列指針front
和rear
應該分別指向鏈表的哪一頭?
typedef struct Node{
ElementType Data;
struct Node *Next;
}QNode;
typedef struct { /*鏈隊列結構*/
QNode *rear; /*指向隊尾結點*/
QNode *front; /* 指向隊頭結點*/
} LinkQueue;
LinkQueue *PtrQ ;
ElementType DeleteQ ( LinkQueue *PtrQ )
{ Qnode *FrontCell;
ElementType FrontElem;
if ( PtrQ->front = NULL) {
printf(“隊列空"); return ERROR;
}
FrontCell = PtrQ->front;
if( PtrQ->front == PtrQ->rear) /* 若隊列只有一個元素*/
PtrQ->front = PtrQ->rear = NULL; /* 刪除後隊列置爲空*/
else
PtrQ->front = PtrQ->front->Next;
FrontElem = FrontCell->Data;
free( FrontCell ); /* 釋放被刪除結點空間*/
return FrontElem;