--- tags: linus2021 --- # 2021q1 Homework1 (lab0) contributed by < `yellow951321` > ## [C Programming Lab](https://www.cs.cmu.edu/afs/cs/academic/class/15213-s20/www/labs/cprogramminglab.pdf) ### Queue struce ``` c= typedef struct { list_ele_t *head; list_ele_t *tail; int size; } ``` 增加 tail 以及 siz e兩個新的變數,以達成作業要求。將 insert_tail 和 size 兩個函式的時間複雜度控制在$O(1)$內。 ### q_new trace--10 會檢測當動態配置記憶體失敗時的情形。因此要記得處理意外狀況。 ``` c= if (!q) return NULL; ``` ### q_free 需要迭代去釋放佇列的值,測試資料中會測試。假如q為NULL時須特別處理。 ``` c= if (!q) return; for (node = q->head; node != NULL;) { list_ele_t *tmp = node; node = node->next; free(tmp->value); free(tmp); } ``` ### q_insert_head 假如輸入的佇列為 NULL 時需要特別處理。 ``` c= if (!q) return false; ``` strcpy 因為沒有指定字串長度會有風險。因此使用 strncpy ,但 strncpy 不會自動補上 `'\0'` 因此需要手動更改。 ``` c= strncpy(newh->value, s, strlen(s)); newh->value[strlen(s)] = 0; ``` ### q_insert_tail 為了滿足 $O(1)$ 的時間複雜度。利用 queue struct 中的 tail 變數儲存佇列的尾端。實做過程和 insert_head 基本相同。 ### q_remove_head 除了需要檢查佇列,還必須檢查 head 是否為NULL。 ``` c= if (!q || !q->head) return false; ``` 然後需要將被移除的 list_element 的記憶體釋放掉以免造成 memory leak ``` c= free(tmp->value); free(tmp); ``` ### q_size 為了達成 $O(1)$ 的時間複雜度,利用變數 size 直接回傳。並且在 insert 和 remove 時維護 size 的正確性。 ``` c= bool q_remove_head(queue_t *q, char *sp, size_t bufsize) { ... --(q->size); ... } bool q_insert_head(queue_t *q, char *s) { ... ++(q->size); ... } ``` 除此之外,也要檢查佇列是否存在。 ``` c= int q_size(queue_t *q) { /* return fasle if q is NULL*/ if (!q) return 0; return q->size; } ``` ### q_reverse 原先長這樣 ```mermaid graph LR subgraph linked list head==>node1==>node2 end subgraph pointer tmp prev end ``` 從 head 開始,依序將每個 node 的 next 設為前面的 node ,但是 tmp 去紀錄 next 的值以免被覆蓋掉。並且用 prev 去指向上一個 node ```mermaid graph LR subgraph linked list node1==>node2 end subgraph linked list2 head end subgraph pointer tmp==>node1 prev==>head end ``` 接著將 node1 往前指 ```mermaid graph LR subgraph linked list node2 end subgraph linked list2 node1==>head end subgraph pointer tmp==>node2 prev==>node1 end ``` 依序做到最尾端並且更新 head 和 tail 即可。 ### q_sort 參考 [merge sort](https://www.geeksforgeeks.org/merge-sort-for-linked-list/)後改寫成符合作業要求的資料結構。 但是在 trace--15 會因為下列程式碼遞迴的特性,造成 stack overflow。 這個函式是在處理 merge 兩個 sublists ``` c= Node* SortedMerge(Node* a, Node* b) { ... if (a->data <= b->data) { result = a; result->next = SortedMerge(a->next, b); } else { result = b; result->next = SortedMerge(a, b->next); } return (result); } ``` 因此改寫成了當前的迭代方式去解決問題。 ``` c= list_ele_t *merge(list_ele_t *frontRef, list_ele_t *backRef) { list_ele_t *result; list_ele_t *tmp; /* Base cases */ if (frontRef == NULL) return backRef; else if (backRef == NULL) return frontRef; /* initial result */ if (strcmp(frontRef->value, backRef->value) < 0) { result = frontRef; frontRef = frontRef->next; } else { result = backRef; backRef = backRef->next; } tmp = result; /* Pick either frontRef or backRef, and recur */ while (frontRef || backRef) { if (!backRef) { tmp->next = frontRef; frontRef = frontRef->next; } else if (!frontRef) { tmp->next = backRef; backRef = backRef->next; } else if (strcmp(frontRef->value, backRef->value) < 0) { tmp->next = frontRef; frontRef = frontRef->next; } else { tmp->next = backRef; backRef = backRef->next; } tmp = tmp->next; } return result; } ``` ### 結果 ![](https://i.imgur.com/Mj9V8J4.png)