1. 程式人生 > 遊戲 >Apple Watch成功執行89年版《波斯王子》

Apple Watch成功執行89年版《波斯王子》

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 ;
}