1.2 - Queue

Introduction of Queue(佇列的基本介紹及應用)

1. 介紹

佇列(Queue)是一種特殊的抽象資料結構,可以用鏈結串列(Link List)或陣列(Array)來表示,佇列的特點是資料的進出是同一方向的,在前端(Front)取出資料,在尾端(Rear)輸入資料,具有先進先出(FIFO, First-In-First-Out))的特性。

2. 基本操作

  • Dequeue(): 從佇列的前端(Front)取出資料。

  • Enqueue(): 將資料放到佇列的尾端(Rear)。

  • IsEmpty(): 檢查是否佇列為空。

  • IsFull(): 檢查佇列是否已滿。(當使用Array製作佇列時需注意是否已滿。)

  1. Dequeue(): 回傳Front指標(指向佇列的前端)的資料。

int dequeue(){
    if (isEmpty() == 1){
        printf("The queue is empty.\n");
        return 0;
    }
    else{
        queue *output = front;
        front = front->next; // the older data
        free(output);
        return output->Data; // return the top node
    }
    return -1;
}

2. Enqueue(): 將資料放入佇列的尾端。

void enqueue(int data){
    // request space for new node
    queue *new_node = (queue *)malloc(sizeof(queue));
    
    // save the data to the new node
    new_node->Data = data;
    new_node->next = NULL;
    
    // push to the back of the queue
    if (isEmpty() == 1){
        front = new_node;
        rear = front;
    }
    else{
        rear->next = new_node; // next of the rear node points to new node
        rear = new_node;
    }
}

3. 輸出結果範例:

Enqueue: 1, 2, 3
Queue: 1, 2, 3
Enqueue: 4, 5
Queue: 1, 2, 3,	4, 5	
Dequeue, the front is: 1
Dequeue, the front is: 2
Queue: 3, 4, 5

完整程式碼: https://github.com/gary30404/Data-Structure/blob/master/1/1.2/queue_in_linklist.c

Circular Link List的特點是不需使用front指標,將rear指向front。

  1. Dequeue(): 回傳Front指標(指向佇列的前端)的資料。

int dequeue(){

    queue *t = (queue *)malloc(sizeof(queue)); //暫時的變數

    if (rear == NULL){
        printf("The queue is empty.\n");
        return 0;
    }
    else{
        if (rear->next == rear){  //代表佇列中只有一筆資料
            t = rear;
            rear = NULL;
            return t->Data;
        }
        else{
            t = rear->next;  //t為front
            rear->next = t->next; //目前的front會被輸出,rear指向當前的front的下一筆資料成為新的front
            return t->Data;
        }
    }
    return -1;
}

2. Enqueue(): 將資料放入佇列的尾端。

void enqueue(int data){
    // request space for new node
    queue *new_node = (queue *)malloc(sizeof(queue));
    
    // save the data to the new node
    new_node->Data = data;
    
    if (rear == NULL){ //Queue原本為空
        new_node->next = new_node;
    }
    else{
        new_node->next = rear->next; //new_node為最後一筆資料,需指向front
        rear->next = new_node; //將new_node加入linklist
    }
    rear = new_node; //新的rear
}

3. 輸出結果範例:

Enqueue: 1, 2, 3
Queue: 1, 2, 3
Enqueue: 4, 5
Queue: 1, 2, 3,	4, 5	
Dequeue, the front is: 1
Dequeue, the front is: 2
Queue: 3, 4, 5

完整程式碼:https://github.com/gary30404/Data-Structure/blob/master/1/1.2/queue_in_circular_linklist.c

  1. 設定佇列的大小

typedef struct queue{
    int *Data;
    int front;
    int rear;
    int MAX_SIZE;
}queue;

2. Dequeue(): 回傳佇列端的資料,並將每筆資料向前推移。所以在此演算法中,front永遠指向第一個元素。

int dequeue(queue *qu){
    if (IsEmpty(qu) == 1){
        printf("The queue is empty.\n");
        return 0;
    }
    else{
        int output = qu->Data[qu->front];
        for (int i = 0;i < qu->rear; i++)
            qu->Data[i] = qu->Data[i+1];
        qu->Data[qu->rear] = 0;
        qu->rear--;
        return output;
    }
    return -1;
}

3. Enqueue(): 將資料放到佇列的後端。

void enqueue(queue *qu, int data){

    if (IsFull(qu) == 1){
        printf("The queue is full.\n");
    }
    else{
        qu->Data[++qu->rear] = data;
    }
}

4. 輸出結果範例:

Enqueue: 1, 2, 3
Queue: 1, 2, 3
Enqueue: 4, 5
Queue: 1, 2, 3,	4, 5	
Dequeue, the front is: 1
Dequeue, the front is: 2
Queue: 3, 4, 5

完整程式碼:https://github.com/gary30404/Data-Structure/blob/master/1/1.2/queue_in_array.c

2.4 以Circular Array來表示佇列的基本操作。

示意圖:

特點:

  • front和rear起始點在0

  • front所指的位置之資料不使用(不算在佇列中)

  • 最多使用n-1個位置

  1. 宣告佇列參數

void create_queue(queue *qu, int size){
    qu->front = 0;
    qu->rear = 0;
    qu->MAX_SIZE = size;
    qu->Data = (int *)malloc(sizeof(int) *size);
}

2. Dequeue(): 回傳佇列端的資料,並將front往下推移。

int dequeue(queue *qu){
    if (qu->front == qu->rear){
        printf("The queue is empty.\n");
        return 0;
    }
    else{
        qu->front = (qu->front + 1) % qu->MAX_SIZE;
        return qu->Data[qu->front];
    }
    return -1;
}

3. Enqueue(): 將資料放到佇列的後端。

void enqueue(queue *qu, int data){

    qu->rear = (qu->rear + 1) % qu->MAX_SIZE;
    if (qu->front == qu->rear){
        printf("The queue is full.\n");
        qu->rear = (qu->rear + qu->MAX_SIZE - 1) % qu->MAX_SIZE;
    }
    else{
        qu->Data[qu->rear] = data;
    }
}

4. 輸出結果範例:

Create a queue which size is 5.
Enqueue: 1,	2, 3
Queue: 1    2    3	
Enqueue: 4
Queue: 1    2    3    4	
Enqueue: 5
The queue is full.
Dequeue, the front is: 1
Dequeue, the front is: 2
Queue: 3    4

完整程式碼:https://github.com/gary30404/Data-Structure/blob/master/1/1.2/queue_in_circular_array1.c

2.5 加上tag改善2.3的空間效率

在這裡使用變數tag來記錄佇列是空或是滿的狀態。

示意圖:

  1. 宣告佇列參數

void create_queue(queue *qu, int size){
    qu->front = 0;
    qu->rear = 0;
    qu->tag = 0;
    qu->MAX_SIZE = size;
    qu->Data = (int *)malloc(sizeof(int) *size);
}

2. Dequeue(): 回傳佇列端的資料,並將front往下推移。

int dequeue(queue *qu){
    if (qu->front == qu->rear && qu->tag == 0){
        printf("The queue is empty.\n");
        return 0;
    }
    else{
        qu->front = (qu->front + 1) % qu->MAX_SIZE;
        if (qu->front == qu->rear) qu->tag = 0; //檢查取出資料後佇列是否為空
        return qu->Data[qu->front];
    }
    return -1;
}

3. Enqueue(): 將資料放到佇列的後端。

void enqueue(queue *qu, int data){

    if (qu->front == qu->rear && qu->tag == 1){
        printf("The queue is full.\n");
    }
    else{
        qu->rear = (qu->rear + 1) % qu->MAX_SIZE;
        qu->Data[qu->rear] = data;
        if (qu->front == qu->rear) qu->tag = 1; //檢查輸入資料後佇列是否是滿的狀態
    }
}

4. 輸出結果範例:

Create a queue which size is 5.
Enqueue: 1,	2, 3
Queue: 1    2    3	
Enqueue: 4
Queue: 1    2    3    4	
Enqueue: 5
The queue is full.
Dequeue, the front is: 1
Dequeue, the front is: 2
Queue: 3    4

完整程式碼:https://github.com/gary30404/Data-Structure/blob/master/1/1.2/queue_in_circular_array2.c

Last updated