Apple Watch成功執行89年版《波斯王子》
阿新 • • 發佈:2022-01-13
1 概念
佇列是一種先進先出(FIFO,First-In-First-Out)或後進後出(LILO,Last-In-Last-Out)的線性表,通常用連結串列或者陣列來實現。
佇列只能在隊尾插入元素(入隊),只能在隊首刪除元素(出隊)。
2 基本操作
2.1 結構定義
實現佇列需要引入兩個變數,head用於標記隊首元素的位置,tail用來標記隊尾元素的位置;
// 普通佇列的結構定義 typedef struct Queue { int *data; int head, tail, length; } Queue; // 迴圈佇列的結構定義(順序表) typedef struct Queue { int *data; int head, tail, length; int count; // 迴圈佇列中元素的個數 } Queue; // 鏈佇列的結構定義 typedef struct Node { int data; struct Node *next; } Node; typedef struct Queue { Node head, *tail; int length; } Queue;
2.2 出隊(head後移)
2.3 入隊(tail後移)
3 普通佇列的“假溢位”問題
對於普通佇列而言,一旦隊列出隊發生,這就意味著有了空閒的空間,然而這些空閒空間並不會被使用。當多次向佇列執行入隊操作,直到tail標記指向了佇列容量的上限時,就有出現“假溢位”現象。如何避免“假溢位”呢?使用迴圈佇列,通過累計佇列元素的個數來判斷佇列的容量上限,而不是簡單地通過tail標記做判斷;或者通過鏈佇列來實現。
4 程式碼演示
4.1 迴圈佇列(入隊+擴容、出隊)
// 結構定義 typedef struct Queue { int *data; int head, tail, length; int count; } Queue; // 建立佇列 Queue *init(int n) { Queue *q = (Queue *)malloc(sizeof(Queue)); q->data = (int *)malloc(sizeof(int) * n); q->length = n; q->head = q->tail = 0; q->count = 0; return q; } // 清空佇列 void clear(Queue *q) { if (q == NULL) return ; free(q->data); free(q); return ; } // 佇列判空操作 int empty(Queue *q) { return q->count == 0; } // 獲取隊首元素 int front(Queue *q) { return q->data[q->head]; } // 入隊 int push(Queue *q, int val) { if (q == NULL) return 0; // 佇列已滿,給佇列擴容 if (q->count == q->length) { if (!expand(q)) { printf(RED("fail to expand!\n")); return 0; } printf(GREEN("success to expand! the new size = %d\n"), q->length); } q->data[q->tail++] = val; if (q->tail == q->length) q->tail = 0; // 迴圈佇列首尾位置轉換 q->count += 1; return 1; } // 出隊 int pop(Queue *q) { if (q == NULL) return 0; if (empty(q)) return 0; q->head += 1; if (q->head == q->length) q->head = 0; // 迴圈佇列首尾位置轉換 q->count -= 1; return 1; } // 遍歷 void output(Queue *q) { printf("Queue(%d) : [", q->count); for (int i = q->head, j = 0; j < q->count; j++) { j && printf(", "); printf("%d", q->data[(i + j) % q->length]); } printf("]\n"); return ; } // 擴容 int expand(Queue *q) { int extr_size = q->length; int *temp; while (extr_size) { temp = (int *)malloc(sizeof(int) * (q->length + extr_size)); if (temp != NULL) break; extr_size >> 1; } if (temp == NULL) return 0; // 擴容失敗(沒有足夠的記憶體) for (int i = q->head, j = 0; j < q->count; j++) { temp[j] = q->data[(i + j) % q->length]; } free(q->data); q->data = temp; q->head = 0, q->tail = q->count; q->length += extr_size; return 1; }
4.2 鏈佇列(入隊、出隊)
// 鏈佇列的結構定義 typedef struct Node { int data; struct Node *next; } Node; typedef struct Queue { Node head, *tail; int length; } Queue; Node *getNewNode(int val) { Node *p = (Node *)malloc(sizeof(Node)); p->data = val; p->next = NULL; return p; } Queue *init_queue() { Queue *q = (Queue *)malloc(sizeof(Queue)); q->head.next = NULL; // q->head.next 指向隊首元素的地址 q->tail = &(q->head); // q->tail指向隊首元素的虛擬地址 q->length = 0; return q; } int empty(Queue *q) { return q->length == 0; } int front(Queue *q) { return q->head.next->data; } int push(Queue *q, int val) { if (q == NULL) return 0; Node *temp = getNewNode(val); q->tail->next = temp; // 入隊操作 q->tail = temp; // 指標後移 q->length += 1; return 1; } int pop(Queue *q) { if (q == NULL) return 0; if (empty(q)) return 0; Node *temp = q->head.next; q->head.next = temp->next; // 指標後移 clear_node(temp); // 出隊操作 q->length -= 1; if (q->length == 0) q->tail = &(q->head); // 佇列為空時,需要將q->tail指向隊首元素的虛擬地址 return 1; } void clear_node(Node *node) { if (node == NULL) return ; free(node); return ; } void clear(Queue *q) { if (q == NULL) return ; Node *p = q->head.next, *temp; while (p != NULL) { temp = p->next; clear_node(p); p = temp; } free(q); return ; } void output(Queue *q) { if (q == NULL) return ; printf("Queue(%d) : [", q->length); for (Node *p = q->head.next; p != NULL; p = p->next) { p != q->head.next && printf(", "); printf("%d", p->data); } printf("]\n"); return ; }