# 2023q1 Homework1 (lab0) ontributed by < `OWaitsInTime` > ## 開發環境 ```bash $ gcc --version gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 $ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 8 On-line CPU(s) list: 0-7 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz CPU family: 6 Model: 158 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 Stepping: 9 CPU max MHz: 4200.0000 CPU min MHz: 800.0000 BogoMIPS: 7200.00 ``` ## 開發過程 :::danger 說好的進度呢? :notes: jserv ::: ### q_new ```cpp /* Create an empty queue */ struct list_head *q_new() { struct list_head *head = malloc(sizeof(struct list_head)); if (!head) return NULL; INIT_LIST_HEAD(head); return head; } ``` ### q_free 最開始的想法是用指標記錄上一個節點 `queue.h` 中 `q_release_element` 可以用來釋放指標的記憶體 ```cpp /* Free all storage used by queue */ void q_free(struct list_head *l) { if (!l) return; struct list_head *led = l->prev; struct list_head *folo = led->prev; while (tmp != l){ tmp = tmp->prev; q_release_element(l->prev); l->prev = tmp; } free(tmp); } ``` `q_release_element` 只能釋放 `element_t` 結構,重看架構圖 head的部分是 `list_head` 沒有儲存value,而其他部分是 `element_t` ![](https://hackmd.io/_uploads/ByHFSCRit.png) 因為 `q_release_element` 會失去 next 的資料,所以額外使用一個指標在 release 後連結資料 ```cpp void q_free(struct list_head *l) { if (!l) return; struct list_head *fnode = l->next; struct list_head *lnode = l->next->next; while (lnode != l) { lnode = lnode->next; q_release_element(list_entry(fnode, element_t, list)); fnode = lnode->prev; } q_release_element(list_entry(fnode, element_t, list)); free(l); } ``` ### q_insert_head 要求 ```Return: true for success, false for allocation failed or queue is NULL``` 首先判斷要插入的 ```insert``` 以及要被插入的 ```head``` 是否存在,而 ```list_add``` 可以把節點插入到 list 的開頭 ```cpp bool q_insert_head(struct list_head *head, char *s) { if (!head) return false; element_t *insert = malloc(sizeof(element_t)); if (!insert) return false; insert->value = strdup(s); list_add(&new->list, head); return true; } ``` :::warning ERROR: Failed to save copy of string in queue ::: 沒有考慮到 ```insert->value == NULL``` 的狀況 ```cpp bool q_insert_head(struct list_head *head, char *s) { if (!head) return false; element_t *insert = malloc(sizeof(element_t)); if (!insert) return false; insert->value = strdup(s); if (!insert->value){ free(insert); return false; } list_add(&new->list, head); return true; } ``` ### q_insert_tail 把 ```q_insert_head``` 中的 ```list_add``` 改成 ```list_add_tail``` ```cpp bool q_insert_tail(struct list_head *head, char *s) { if (!head) return false; element_t *insert = malloc(sizeof(element_t)); if (!insert) return false; insert->value = strdup(s); if (!insert->value) { free(insert); return false; } list_add_tail(&insert->list, head); return true; } ``` ### q_remove_head 要求 ```Return: the pointer to element, %NULL if queue is NULL or empty.``` C 字串需要尾端的 ```'\0'``` 字元來判斷字串結束 ```cpp element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize) { if (!head || list_empty(head)) return NULL; element_t *node = list_entry(head->next, element_t, list); if (sp) { strncpy(sp, node->value, bufsize - 1); sp[bufsize - 1] = '\0'; } list_del(&node->list); return node; } ``` ### q_remove_tail 把 ```q_remove_head``` 中 ```head->next``` 改成 ```head_prev``` ```cpp element_t *q_remove_tail(struct list_head *head, char *sp, size_t bufsize) { if (!head || list_empty(head)) return NULL; element_t *node = list_entry(head->prev, element_t, list); strncpy(sp, node->value, bufsize - 1); sp[bufsize - 1] = '\0'; list_del(&node->list); return node; } ``` ### q_size 要求 ```Return: the number of elements in queue, zero if queue is NULL or empty``` ```cpp int q_size(struct list_head *head) { if (!head || list_empty(head)) return 0; int len = 0; struct list_head *li; list_for_each (li, head) len++; return len; } ``` ### q_delete_mid 使用 ```q_size``` 得到 queue 的節點數並利用 (x/2)+1 找到中間節點是第幾個 ```cpp bool q_delete_mid(struct list_head *head) { if (!head || list_empty(head)) return false; int mid = (q_size(head) / 2) + 1; struct list_head *current = head; while (mid != 0) { current = current->next; mid--; } q_release_element(list_entry(current, element_t, list)); return true; } ``` ### q_delete_dup ### q_swap ```list.h``` 中 ```list_swap``` 可以交換兩個節點,當 leader 指標指向 ```head``` 或 ```head->next``` 時就不做交換 ```cpp void q_swap(struct list_head *head) { if (!head || list_empty(head)) return; struct list_head *l = head->next->next; struct list_head *f = head->next; while (l != head && l != head->next) { list_swap(l, f); l = f->next->next; f = f->next; } } // 發生錯誤 ueue.c:154:9: error: implicit declaration of function ‘list_swap’ [-Werror=implicit-function-declaration] 154 | list_swap(n, t->next); | ^~~~~~~~~ cc1: all warnings being treated as errors make: *** [Makefile:54:queue.o] 錯誤 1 ``` 把 ```list_swap``` 用 ```list_move``` 替代 ```cpp void q_swap(struct list_head *head) { if (!head || list_empty(head)) return; struct list_head *l = head->next->next; struct list_head *f = head->next; while (l != head && l != head->next) { list_move(l, f); l = f->next->next; f = f->next; } } ``` ### q_reverse ### q_reverseK ### q_sort ### q_descend ### q_merge ### q_shuffle