資料結構學習(六)——迴圈順序佇列的操作
阿新 • • 發佈:2019-02-16
佇列是一種只允許在表的一端(稱為隊尾)進行插入,而在另一端(稱為隊頭)進行刪除的線性表,是線性表的一種特例。
順序佇列是用陣列結構來表示的。為了描述佇列的這種結構,我們需要兩個表明隊頭和隊尾的指標,規定隊頭指標指向佇列頭結點的前一個位置,而隊尾指標指向佇列的尾結點。而為什麼又會用到迴圈佇列呢,因為為了防止“假上溢”對空間造成的浪費。“假上溢”是這麼來的,先說“上溢”和“下溢”。下溢就是當空對時,如果再做出隊操作,則會產生“下溢”。
當隊滿時,再做入對操作會產生“上溢”。但是,如果當前尾指標等於陣列的上界,即使佇列不滿,再做入隊操作也會引起溢位。這種現象就是“假上溢”。然而有了迴圈佇列,我們就可以避免假上溢的問題了。但是迴圈佇列還是有一個問題,就是判斷佇列與隊滿的情況。如果按照前面的規定,隊頭指標指向佇列頭結點的前一個位置,而隊尾指標指向佇列的尾結點。那麼是分辨不出來隊滿與隊空的關係的。我看書中列出了3種解決此問題的方法。不過第三種最適合,它是採用少用一個節點空間,即頭指標指向的空間不使用。這樣的話。當front等於rear時,隊空;入隊後,當尾指標加1後等於頭指標,即:(rear+1)%maxsize = front.則說明這時佇列已滿。
下面是對迴圈順序佇列操作的一個整體程式碼:
#include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 typedef struct node { int data[MAXSIZE]; int front; //存放佇列頭地址 int rear; //存放佇列尾地址 }sequeue; void Sequeue_SetNull(sequeue *q); //佇列置空 int Sequeue_Empty(sequeue *q); //判斷佇列是否為空 int Sequeue_GetFront(sequeue *q); //得到佇列頭結點 int Sequeue_In(sequeue *q, int dat); //入對操作 int Sequeue_Out(sequeue *q); //出隊操作 void ShowSequeue(sequeue *q); //輸出顯示佇列 int main(void) { int num, i, dat, choice, ans; sequeue *q; q = (sequeue*)malloc(sizeof(sequeue)); printf("迴圈順序佇列的操作練習:\n"); printf("輸入你想建立佇列的資料個數:\n"); scanf("%d", &num); if(num>MAXSIZE-1) { printf("佇列結點數大於最大允許空間!\n"); return 0; } Sequeue_SetNull(q); printf("請依次輸入佇列資料:\n"); for(i=1; i<num+1; i++) //迴圈輸入佇列結點資料 { scanf("%d", &dat); q->data[i] = dat; q->rear = i; } while(1) { printf("佇列操作:\n"); printf("1.取佇列結點\n"); printf("2.入隊操作\n"); printf("3.出隊操作\n"); printf("4.輸出佇列\n"); printf("5.退出程式\n"); printf("做出選擇:\n"); scanf("%d", &choice); switch(choice) { //取佇列頭結點 case 1: dat = Sequeue_GetFront(q); printf("頭結點為:%d\n", dat); break; //入隊 case 2: printf("輸入你想入隊的資料:\n"); scanf("%d", &dat); ans = Sequeue_In(q, dat); if(ans) printf("入隊成功!\n"); else printf("入隊失敗!\n"); break; //出隊 case 3: ans = Sequeue_Out(q); if(ans) printf("出隊成功!\n"); else printf("出隊失敗!\n"); break; //輸出顯示佇列 case 4: ShowSequeue(q); break; //退出程式 case 5: return 0; break; default: printf("選擇無效!\n"); break; } } } //佇列置空 void Sequeue_SetNull(sequeue *q) { q->rear = 0; //其中陣列第一個節點空間不使用(即下標為0陣列元素),用作佇列滿與空的區別 q->front = 0; } //判斷佇列是否為空 int Sequeue_Empty(sequeue *q) { if(q->front == q->rear) //頭結點等於尾結點即表示佇列為空 return 1; else return 0; } //取得佇列頭結點 int Sequeue_GetFront(sequeue *q) { if(Sequeue_Empty(q)) //取頭結點先要判斷佇列是否為空 { printf("佇列空!\n"); return 0; } else return q->data[(q->front+1) % MAXSIZE]; } //入隊 int Sequeue_In(sequeue *q, int dat) { if((q->rear+1)%MAXSIZE == q->front) //入隊先要判斷佇列是否已經滿了 return 0; else { q->rear = (q->rear+1) % MAXSIZE; //使用求模運算 q->data[q->rear]= dat; return 1; } } //出隊 int Sequeue_Out(sequeue *q) { if(Sequeue_Empty(q)) //出隊先要判斷佇列是否為空 return 0; else { q->front = (q->front+1) % MAXSIZE; //求模運算 return q->data[q->front]; } } //輸出顯示佇列 void ShowSequeue(sequeue *q) { int i; i = q->front+1; while(i != q->rear+1) { printf("%d ", q->data[i]); i++; } printf("\n"); }