1.隊列的基本概念
隊列(Queue)簡稱隊,是一種操作受限的表,只允許在表的一端進行插入,另一端進行刪除。向隊列中插入元素稱為入隊或進隊,刪除元素稱為出隊或離隊,操作特性為先進先出。
隊列的“先入先出”特性是指:最后插入的元素總是被最后刪除,每次從隊列刪除的總是最早插入的元素。
2.隊列的順序存儲
#define MaxSize 50 typedef struct{ ElemType data[MaxSize]; int front,rear; }SqQueue;
初始狀態(隊空狀態):Q.front=Q.rear=0。
進隊操作:隊不滿時,先將元素加到隊尾,再將隊尾指針加1。
出隊操作:隊不空時,先將隊頭元素取出,再將隊頭指針加1。
3.循環隊列
在普通隊列中,每次入隊和進隊操作都會將隊頭隊尾指針增加,會造成一種“假溢出”問題,這時候就需要使用循環隊列。將順序隊列從邏輯上視為一個環狀空間,此為循環隊列。
初始時:Q.front=Q.rear=0。
隊首指針進1:Q.front=(Q.front+1)%MaxSize。
隊尾指針進1:Q.rear=(Q.rear+1)%MaxSize。
循環隊列的問題:當隊空和隊滿時,均有Q.front==Q.rear。該怎么判斷隊空還是隊滿?
解決:方案1,犧牲一個單元來區分隊空還是隊滿,入隊時少用一個隊列單元,使隊滿條件為:(Q.rear+1)%MaxSize==Q.front,隊空條件為:Q.front==Q.rear。
方案2,增設表示元素個數的數據單元,隊空時:Q.size==0,隊滿時:Q.size==MaxSize。
方案3:增設tag變量,tag等於0時,若Q.front==Q.rear,則為隊空,tag等於1時,Q.front==Q.rear,則為隊滿。
//初始化 void InitQueue(SqQueue &Q){ Q.rear=Q.front=0; } //隊的判空 bool isEmpty(SqQueue Q){ if(Q.rear==Q.front) { return true; } else{ return false;} } //入隊 bool EnQueue(SqQueue &Q,ElemType x){ if((Q.rear+1)%MaxSize==Q.front){ return false; } Q.data[Q.rear]=x; Q.rear=(Q.rear+1)%MaxSize; return true; } //出隊 bool DeQueue(SqQueue &Q,ElemType x){ if(Q.rear==Q.front){ return false;} x=Q.data[Q.front]; Q.front=(Q.fornt+1)%MaxSize; return true; }
4.隊列的鏈式存儲
實際上是一個同時帶有隊頭指針和隊尾指針的單鏈表,頭指針指向頭結點,尾指針指向尾結點。
typedef struct{ ElemType data; struct LinkNode *next; }LinkNode; typedef struct{ LinkNode *rear,*front; }LinkQueue;
當Q.front==NULL且Q.rear==NULL時,鏈式隊列為空。
//初始化 void InitQueue(LinkQueue &Q){ Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode)); Q.front->next=NULL; } //隊判空 bool isEmpty(LinkQueue Q){ if(Q.front==Q.rear){ return true; } else{ return false; } } //入隊 void EnQueue(LinkQueue &Q,ElemType x){ LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode)); s->data=x; s->next=NULL; Q.rear->next=s; Q.rear=s; } //出隊 bool DeQueue(LinkQueue &Q,ElemType &x){ if(Q.front==Q.rear){ return false; } LinkNode *p=Q.front->next; x=p->data; Q.front->next=p->next; if(Q.rear==p) Q.rear=Q.front; //若原隊列中只有一個結點,刪除后變空。 free(p); return true; }
5.雙端隊列
雙端隊列是指允許兩端都可以進行入隊和出隊的隊列,將隊列兩端分別稱為前端和后端,兩端都可以入隊和出隊。