說明
佇列是一種先進先出的資料結構,想像您在管子中放入球,最先放入的球在另一端會最先跑出來,在這邊介紹如何使用陣列來實作佇列。
解法
使用陣列來實作佇列,我們必須保留兩個旗標,假設front指向佇列的前端,rear向佇列的後端,我們每次從佇列後端加入一個資料,rear就加1指向最後一個資料,每次從佇列前端取出一個資料,front就加1指向佇列的最前端,如下圖所示:
這是最簡單的佇列實作,但是由於陣列的大小必須先決定,所以這種線性的結構有個問題,front與rear會到達陣列的後端,而這個陣列就不能再使用了,
為了解決這個問題,將陣列當作環狀來使用,當front或rear到達陣列後端時,就重新從陣列前端再循環,也就是形成環狀佇列,如下圖所示:
不過陣列的容量還是受限制,所以這個陣列還是會滿的,當front = rear時,佇列就滿了;佇列的基本操作有五項:新增佇列、加入資料、顯示前端資料、取出前端資料、顯示所有的佇列元素。
實作
#include <stdio.h> #include <stdlib.h> #define N 10
void createq(int[], int*, int*); void showfront(int[], int, int); void add(int[], int*, int*, int); void del(int[], int*, int*); void showqueue(int[], int, int);
int main(void) { int queue[N]; int front, rear; int input, select;
createq(queue, &front, &rear);
while(1) { printf("\n\n請輸入選項(-1結束):"); printf("\n(1)插入值至佇列"); printf("\n(2)顯示佇列前端"); printf("\n(3)刪除前端值"); printf("\n(4)顯示所有內容"); printf("\n$c>"); scanf("%d", &select); if(select == -1) break;
switch(select) { case 1: printf("\n輸入值:"); scanf("%d", &input); add(queue, &front, &rear, input); break; case 2: showfront(queue, front, rear); break; case 3: del(queue, &front, &rear); break; case 4: showqueue(queue, front, rear); break; default: printf("\n選項錯誤!"); } }
printf("\n");
return 0; }
void createq(int queue[], int* front, int* rear) { int i;
for(i = 0; i < N; i++) queue[i] = 0;
*front = *rear = 0; }
void showfront(int queue[], int front, int rear) { if(front == rear) printf("\n佇列為空!"); else printf("%d", queue[(front+1) % N]); }
void add(int queue[], int* front, int* rear, int data) { int f, r; f = *front; r = *rear; r = (r+1) % N;
if(f == r) { printf("\n佇列已滿!"); return; }
queue[r] = data; *rear = r; }
void del(int queue[], int* front, int* rear) { int f, r; f = *front; r = *rear;
if(f == r) { printf("\n佇列為空!"); return; }
f = (f+1) % N; *front = f; }
void showqueue(int queue[], int front, int rear) { int i;
printf("\n佇列內容:"); for(i = (front+1) % N; i <= rear; i++) printf("%d ", queue[i]); }
補充
您如果仔細演算過上面的環狀佇列,您會發現有一個空間會被浪費掉,這是因為判斷佇列已滿或已空的條件都是front =
rear,浪費一個空間對現在的電腦記憶體如此足夠來說,並不是個大問題,如果您一定要解決這個問題,可以多使用一個flag來判斷,如果flag設定為
1且front = rear,則表示佇列已滿,如果flag設定為0則front =
rear,則表示佇列已空,這樣就不會浪費一個佇列空間了,提供改良後的虛擬碼如下:
Procedure add(queue, n, front, rear, flag, data) if(front = rear and flag = 1) then call QUEUE_FULL queue(rear) <- data if(front = rear) then flag <- 1 end add
Procedure del(queue, n, front, rear, flag, data) if(front = rear and flag = 0) then call QUEUE_EMPTY front <- (front+1) mod n if(front = rear) then flag <- 1 end del
|
|