队列(常用数据结构之一)
隊列
隊列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。
一個隊列為z=(a1,a2,…,an), 如圖
那么a1為對頭元素,an為隊尾元素。最早進入隊列的元素也會最早出來,只有當最先進入隊列的元素都出來以后,后進入的元素才能退出。
在日常生活中,人們去銀行辦理業務需要排隊,這就類似我們提到的隊列。每一個新來辦理業務的需要按照機器自動生成的編號等待辦理,只有前面的人辦理完畢,才能輪到排在后面的人辦理業務。新來的人進入排隊狀態就相當于入隊,前面辦理完業務離開的就相當于出隊。
隊列有兩種存儲表示:順序存儲和鏈式存儲。采用順序存儲結構的隊列被稱為順序隊列,采用鏈式存儲結構的隊列稱為鏈式隊列。
基本運算
InitQueue() ——初始化隊列 EnQueue() ——進隊列 DeQueue() ——出隊列 IsQueueEmpty() ——判斷隊列是否為空 IsQueueFull() ——判斷隊列是否已滿順序隊列
由于順序隊列的底層使用的是數組,因此需預先申請一塊足夠大的內存空間初始化順序隊列。除此之外,為了滿足順序隊列中數據從隊尾進,隊頭出且先進先出的要求,我們還需要定義兩個指針(top 和 rear)分別用于指向順序隊列中的隊頭元素和隊尾元素。
隊列為空時,隊頭指針front和隊尾指針rear都指向下標為0的存儲單元,當元素a,b,c,d,e,f,g依次進入隊列后,元素ag分別存放在數組下標為06的存儲單元中,隊頭指針front指向元素a,隊尾指針指rear向元素g的下一位置。如圖所示。
假溢出
在順序隊中,當尾指針已經到了數組的上界,不能再有入隊操作,但其實數組中還有空位置,這就叫“假溢出”。解決假溢出的途徑———采用循環隊列。
例如在圖中隊列刪除a和b,然后依次插入h、i和j,當插入j后,就會出現隊尾指針rear越出數組的下界造成“假溢出”,如圖
順序循環隊列
為充分利用向量空間,克服"假溢出"現象的方法是:將向量空間想象為一個首尾相接的圓環,并稱這種向量為循環向量。存儲在其中的隊列稱為循環隊列(Circular Queue)。即:循環隊列中進行出隊、入隊操作時,頭尾指針仍要加1,朝前移動。只不過當頭尾指針指向向量上界(QueueSize-1)時,其加1操作的結果是指向向量的下界0。
隊空和隊滿
在循環隊列中,隊空和隊滿時隊頭front和隊尾指針rear同時都會指向同一存儲單元,即front==rear,如圖所示。
隊空
隊滿
如何區分隊空和隊滿呢?有以下兩種方法:
(1)增加一個標志位。設標志位為tag,初始時,tag=0;當入隊成功,則tag=1;出隊成功,tag=0。則判斷隊空的條件為:frontrear&&tag0;隊滿的條件為:frontrear&&tag1;
(2)少用一個存儲單元。隊空的判斷條件為frontrear;隊滿的判斷條件為front(rear+1)%QueueSize。
隊滿的狀態如圖。
存儲結構
#define MAXQSIZE 5 // 存儲空間的初始分配量 typedef struct {ElemType *base;int front;int rear;int maxSize; } SqQueue;基本運算
初始化
Status InitQueue(SqQueue &Q) {//分配存儲空間Q.base = (ElemType*)malloc(MAXQSIZE * sizeof(ElemType));if(!Q.base) exit(OVERFLOW);//置Q為空隊列Q.front = Q.rear = 0;Q.maxSize = MAXQSIZE;return OK; }判隊列是否為空
Status QueueEmpty(SqQueue Q) {if(Q.rear == Q.front) return TRUE;else return FALSE; }入隊函數
Status EnQueue(SqQueue &Q, ElemType e) {if((Q.rear + 1) % MAXQSIZE == Q.front)//隊列已滿return ERROR;Q.base[Q.rear] = e;//插入隊尾Q.rear = (Q.rear + 1) % MAXQSIZE;//尾部指針后移,如果到最后則轉到頭部return OK; }出隊函數
Status DeQueue(SqQueue &Q, ElemType &e) {if(Q.front == Q.rear) //隊列空return ERROR;//返回隊頭元素e = Q.base[Q.front]; //隊頭指針后移,如到最后轉到頭部Q.front = (Q.front + 1) % MAXQSIZE; return OK; }輸出循環隊列函數
void OutQueue(SqQueue Q) { ElemType e;if(QueueEmpty(Q)){printf("這是一個空隊列!");} else {while(!QueueEmpty(Q)){DeQueue(Q, e);printf("%6d", e);}printf("\n");} }輸出循環隊列長度
Status QueueLength(SqQueue Q) {return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE; }銷毀隊列
Status ClearQueue(SqQueue Q) {///銷毀隊列Q,Q不再存在if(Q.base)free(Q.base);Q.base = NULL;Q.front = Q.rear = 0;return OK; }主函數
int main() { SqQueue q;int cord; ElemType a;printf("第一次使用必須初始化!\n");//調用初始化算法InitQueue(q); do{printf("\n 主菜單 \n");printf(" 1 初始化循環隊列 ");printf(" 2 進隊一個元素 ");printf(" 3 出隊一個元素 ");printf(" 4 隊列長度 ");printf(" 5 銷毀隊列 ");printf(" 6 結束程序運行 ");printf("\n------------------------------------------------------------------\n");printf("請輸入您的選擇( 1, 2, 3, 4, 5, 6)");scanf("%d", &cord);printf("\n");switch(cord) {case 1:InitQueue(q); //調用初始化算法;OutQueue(q);break;case 2:printf("請輸入要插入的數據元素:a=");scanf("%d", &a);EnQueue (q, a); //調用進隊算法;printf("%d 進隊之后的隊列:",a);OutQueue(q);break;case 3:DeQueue (q, a); //調用出隊算法;printf("隊頭元素 %d 出隊之后的隊列:", a);OutQueue(q);break;case 4:printf("該隊列長度為: %d", QueueLength(q));break;case 5:ClearQueue(q);break;case 6:exit(0);}} while(cord <= 4);return 0; }總結
以上是生活随笔為你收集整理的队列(常用数据结构之一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用队列实现车厢编组
- 下一篇: 栈(顺序栈)