隊列(queue)
隊列是一種先進先出(first in first out,FIFO)的線性表。它只允許在表的一端(隊尾/rear)插入元素,而在另一端(隊頭/front)刪除元素。插入操作稱爲入隊或進隊,刪除操作稱爲出隊或離隊。隊列示意圖如下:
1、 順序隊
隊列的順序存儲結構需要使用一個數組和兩個整型變量來實現,數組用於存儲隊列中的所有元素,兩個整型變量分別用於存儲隊頭元素和隊尾元素的下標位置,分別稱爲隊頭指針和隊尾指針。
假定隊列的元素個數不超過MaxSize,所有的元素的數據類型都是ElemType,則順序隊列類型SqQueue定義如下:
typedefstruct
{
ElemType data[MaxSize];
Int front,rear;
}SqQueue;
在順序隊列*q中,隊空的條件是q->front==q->rear;隊滿的條件是q->rear==MaxSize-1;元素e入隊的操作是先將隊尾指針加1,然後將元素e放入隊尾;出隊操作是先將隊頭指針加1,然後取出隊頭處的元素;隊尾指針總是指向當前隊列中的隊尾元素,而隊頭指針總是指向當前隊列中隊頭元素的前一個位置。
順序隊的基本運算實現如下:
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 20 //隊列元素最大個數
typedef char ElemType; //隊列元素類型
typedef struct //順序隊
{
ElemType data[MaxSize]; //數據元素
int front; //對頭指針
int rear; //隊尾指針
}SqQueue;
void InitQueue(SqQueue *&q) //初始化隊列
{
q=(SqQueue *)malloc(sizeof(SqQueue));
q->front=q->rear=-1;
}
void DestoryQueue(SqQueue *&q) //銷燬隊列
{
free(q);
}
bool QueueEmpty(SqQueue *q) //判斷隊列是否爲空
{
return (q->front==q->rear);
}
bool QueueFull(SqQueue *q) //判斷隊列是否已滿
{
return (q->rear==MaxSize-1);
}
bool EnQueue(SqQueue *&q, ElemType e) //入隊(插入元素)
{
if(q->rear==MaxSize-1) //隊列已滿,不能再插入
return false;
q->rear++;
q->data[q->rear]=e;
return true;
}
bool DeQueue(SqQueue *&q, ElemType &e) //出隊(刪除元素)
{
if(q->front==q->rear) //隊列爲空,無法刪除
return false;
q->front++;
e=q->data[q->front];
return true;
}
int main()
{
...;
return 0;
}
2、 環形隊列
將數組的前端和後端連接起來,形成環形的順序表——環形隊列。
環形隊列的基本運算實現如下:
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10 //隊列元素最大個數
typedef char ElemType; //隊列元素類型
typedef struct //環形隊列
{
ElemType data[MaxSize]; //數據元素
int front; //對頭指針
int rear; //隊尾指針
}QuType;
void InitQueue(QuType *&qu) //初始化隊列
{
qu=(QuType *)malloc(sizeof(QuType));
qu->front=qu->rear=0;
}
void DestoryQueue(QuType *&qu) //銷燬隊列
{
free(qu);
}
bool QueueEmpty(QuType *&qu) //判斷隊列是否爲空
{
return (qu->front==qu->rear);
}
bool QueueFull(QuType *&qu) //判斷隊列是否已滿
{
return (qu->front==(qu->rear+1)%MaxSize);
}
bool EnQueue(QuType *&qu, ElemType e) //入隊
{
if(qu->front==(qu->rear+1)%MaxSize) //注意!
return false;
qu->rear=(qu->rear+1)%MaxSize;
qu->data[qu->rear]=e;
return true;
}
bool DeQueue(QuType *&qu, ElemType &e) //出隊
{
if(qu->front==qu->rear)
return false;
qu->front=(qu->front+1)%MaxSize;
e=qu->data[qu->front];
return true;
}
int main()
{
...;
return 0;
}
3、 鏈隊
隊列的鏈式存儲結構通過由結點構成的單鏈表實現,此時只允許在單鏈表的表頭進行刪除操作和在單鏈表的表尾進行插入操作,因此需要兩個指針:隊首指針front和隊尾指針rear。用front指向隊首結點,用rear指向隊尾結點。用於存儲隊列的單鏈表成爲鏈隊。
鏈隊(帶頭結點)中數據結點的類型QNode定義如下:
typedefstruct qnode
{
ElemType data;
struct qnode *next;
}QNode; //鏈隊數據結點類型定義
鏈隊結點的類型LinkQueue定義如下:
typedefstruct
{
QNode *front;
QNode *rear;
}LinkQueue; //鏈隊類型定義
鏈隊的基本運算實現如下:
#include<stdio.h>
#include<stdlib.h>
typedef char ElemType;
typedef struct qNode
{
ElemType data;
struct qNode *next;
}QNode; //數據結點
typedef struct
{
QNode *front; //隊頭指針
QNode *rear; //隊尾指針
}LinkQueue; //鏈隊結點
void InitQueue(LinkQueue *&q) //初始化鏈隊
{
QNode *p=(QNode *)malloc(sizeof(QNode)); //創建頭結點
if(!p)
{
printf("內存分配失敗\n");
exit(1);
}
p->next=NULL;
q=(LinkQueue *)malloc(sizeof(LinkQueue)); //分配鏈隊結點空間
if(!q)
{
printf("內存分配失敗\n");
exit(1);
}
q->front=q->rear=p;
}
void DestoryQueue(LinkQueue *&q) //銷燬鏈隊
{
QNode *p;
while(q->front!=NULL)
{
p=q->front;
q->front=p->next;
}
free(p);
}
bool QueueEmpty(LinkQueue *q) //判斷隊列是否爲空
{
return (q->front->next==NULL);
}
void EnQueue(LinkQueue *&q, ElemType e) //入隊
{
QNode *p;
p=(QNode *)malloc(sizeof(QNode)); //創建新結點
if(!p)
{
printf("內存分配失敗!\n");
exit(1);
}
p->data=e;
p->next=NULL;
q->rear->next=p;
q->rear=p;
}
bool DeQueue(LinkQueue *&q, ElemType &e) //出隊
{
QNode *p;
if(q->front->next==NULL) //隊列爲空,操作無效
return false;
p=q->front->next;
e=p->data;
q->front->next=p->next;
if(p->next==NULL) //刪除最後一個結點後,將尾指針指向頭結點
q->rear=q->front;
free(p);
return true;
}
int main()
{
...;
return 0;
}
幾個注意點:
1、順序隊和環形隊列的隊空條件均是q->front==q->rear;順序隊的隊滿條件是p->rear==MaxSize-1,而環形隊列的隊滿條件是q->front==(q->rear+1)%MaxSize;
2、順序隊和環形隊列初始化的不同,導致最後存儲空間上的元素不一樣。順序隊的初始化:q->front=q->rear=-1,所以元素從q->data[0]開始存儲;而環形隊列的初始化:q->front=q->rear=0,所以元素從q->data[1]開始存儲,q->data[0]空閒;
3、順序隊列滿足隊滿條件時可能是假溢出(如p->rear==MaxSize-1,此時即使出隊幾個數據仍然滿足了隊滿條件,但已經騰出了若干個空間,此時就是假溢出),而環形隊列滿足隊滿條件就是沒有多餘的存儲空間了;
4、順序隊中的元素個數是rear-front,環形隊列中的元素個數是(rear-front+MaxSize)%MaxSize;
5、鏈隊的初始化,創建頭結點的同時,爲鏈隊結點分配內存空間;
6、出隊時,當刪除最後一個結點後,尾指針也隨之釋放,所以應該將尾指針重新賦值,指向頭結點。
2014年7月29日星期二