# 2019q1 Homework1 (lab0) contributed by < `yicheng11` > ## 開發環境 ```shell $ uname -a Linux c44044064-Thinkpad 4.18.0-15-generic #16~18.04.1-Ubuntu SMP Thu Feb 7 14:06:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux $ gcc --version gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0 ``` ## 作業要求 * 實做FIFO及LIFO queue,滿足以下功能 * q_new:建立一個新的空 queue * q_free:把 queue 整個清除掉 * q_insert_head:在 queue 的 head 新增新的元素 * q_insert_tail:在 queue 的 tail 新增新的元素 * q_remove_head:移除在 queue 的 head 的元素 * q_size:計算 queue 中有多少元素 * q_reverse:把 queue 反轉 其中 q_insert_tail 與 q_size 的時間複雜度要求為 $O(1)$ * 解釋自動評分系統運作原理還有提及 qtest 的行為和裡頭的技巧 ## 實作 ### queue_t ```clike= typedef struct { list_ele_t *head; list_ele_t *tail; int size; } queue_t ``` 為了使 q_size 與 q_insert_tail 的時間複雜度為 $O(1)$,利用 size 紀錄 queue 的大小,還有使用一指標指向 queue 的尾端 ### q_new ```clike= queue_t *q_new() { queue_t *q = malloc(sizeof(queue_t)); if (!q) return NULL; q->head = NULL; q->tail = NULL; q->size = 0; return q; } ``` 要考慮到 malloc 失敗的情況 ### q_free ```clike= void q_free(queue_t *q) { if (!q) return; while (q->head) { list_ele_t *temp = q->head; q->head = q->head->next; free(temp->value); free(temp); } free(q); } ``` 循序 free value 再 free list_ele_t,時間複雜度是$O(n)$ ### q_insert_head ```clike= bool q_insert_head(queue_t *q, char *s) { if (!q) return false; list_ele_t *newh = malloc(sizeof(list_ele_t)); if (!newh) return false; int len = strlen(s) + 1; char *ptr = malloc(len * sizeof(char)); if (!ptr) { free(newh); return false; } memset(ptr, 0, len); strncpy(ptr, s, len - 1); newh->value = ptr; newh->next = q->head; if (q->head) { q->head = newh; } else { q->head = q->tail = newh; } q->size++; return true; } ``` 這邊使用 strncpy() 取代 strcpy() 防止 buffer overflow ### q_insert_tail ```clike= bool q_insert_tail(queue_t *q, char *s) { if (!q) return false; list_ele_t *newt = malloc(sizeof(list_ele_t)); if (!newt) return false; int len = strlen(s) + 1; char *ptr = malloc(len * sizeof(char)); if (!ptr) { free(newt); return false; } memset(ptr, 0, len); strncpy(ptr, s, len - 1); newt->value = ptr; newt->next = NULL; if (q->head) { q->tail->next = newt; q->tail = newt; } else { q->tail = q->head = newt; } q->size++; return true; } ``` ### q_remove_head ```clike= bool q_remove_head(queue_t *q, char *sp, size_t bufsize) { /* You need to fix up this code. */ if (!q || !q->size) return false; list_ele_t *tmp = q->head; if (sp) { memset(sp, '\0', bufsize); strncpy(sp, tmp->value, bufsize - 1); } q->head = q->head->next; free(tmp->value); free(tmp); q->size--; return true; } ``` ### q_size ```clike= int q_size(queue_t *q) { if (!q || !q->size) return 0; else return q->size; } ``` 因為在 queue_t 有以 size 紀錄 queue 的大小,所以可以直接回傳,時間複雜度是$O(1)$ ### q_reverse ```clike= void q_reverse(queue_t *q) { list_ele_t *r, *s; if (!q || !q->size) return; r = q->head->next; q->tail = q->head; q->head->next = NULL; for (; r != NULL; q->head = r, r = s) { s = r->next; r->next = q->head; } } ``` 把 queue 裡面的元素反轉 ## 自動評分系統