# 2024q1 Homework1 (lab0) contributed by < [`Ken-LuWeiRu`](https://github.com/Ken-LuWeiRu) > <s># linux2024-homework1</s> :::danger 標題格式固定為 2024q1 Homework1 (lab0),其中 "lab0" 是小寫,2024q1 表示「2024 年第 1 季」。 共筆內容的第二行則為 `contributed by < 你的GitHub帳號名稱 >` 留意各式細節,唯有重視小處並步步為營,方可挑戰原始程式碼規模超越三千七百萬行的 Linux 核心 ::: ## 開發環境 ```shell $ gcc -v gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04) $ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 46 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 24 On-line CPU(s) list: 0-23 Vendor ID: GenuineIntel Model name: 13th Gen Intel(R) Core(TM) i7-13700K CPU family: 6 Model: 183 Thread(s) per core: 2 Core(s) per socket: 16 Socket(s): 1 Stepping: 1 CPU max MHz: 5400.0000 CPU min MHz: 800.0000 BogoMIPS: 6835.20 ``` ## 專案底下個檔案用途 :::danger 詳閱[資訊科技詞彙翻譯](https://hackmd.io/@sysprog/it-vocabulary) ::: 這禮拜才開始學 C 與指標 <s>指針</s>,原本是直接以queue.c來實作,後續才意識到queue.h與list.h早已實作好許多功能,以下是簡單敘述 * `Makefile` : 包含編譯和構建項目的指令。 * `console.c 和 console.h` : 實現qtest的命令行解釋器。 * `harness.c 和 harness.h` : 提供嚴格測試框架的自定義malloc/free/strdup實現。 * `linenoise.c 和 linenoise.h` : 為qtest提供命令行的函數庫。 * `list.h` : 列表頭文件。 * `log2_lshift16.h` : 提供顯示/隱藏Shannon熵的選項。 * `qtest.c` : 測試queue.c,可以生成測試queue * `queue.c 和 queue.h` : 實現隊列的代碼和聲明。 * `random.c 和 random.h` : 生成隨機數的實現和聲明。 * `report.c 和 report.h` : 實現在不同詳細等級打印信息的功能。 * `shannon_entropy.c` : 提供顯示/隱藏Shannon熵的功能。 * `web.c 和 web.h` : 為qtest集成一個小型的Web服務器。 :::danger 無論標題和內文中,中文和英文字元之間要有空白字元 (對排版和文字搜尋有利) ::: ## 實作指定佇列操作 ### q_new :::danger 改進你的漢語表達,什麼是「建立list的頭」? ::: 由於list.h已經提供INIT_LIST_HEAD()來建立list的頭,不該重複撰寫類似的程式碼,因此直接使用。 在測試記憶體空間時,若不足需要返回NULL。 ```diff struct list_head *q_new() { struct list_head *head = malloc(sizeof(struct list_head)); + if (!head) + return NULL; - head->next = head; - head->prev = head; + INIT_LIST_HEAD(head); return head; } ``` ### q_free free首先也需要注意確認是否head是否存在,並且在list.h有提供list_for_each_safe()可以遍歷所有節點,list_first_entry()可以得到第一個元素,改使用後還可以通過效能測驗。 ```diff void q_free(struct list_head *head) { if (!head) return; struct list_head *current, *temp; + list_for_each_safe(current, temp, head) { + element_t *entry = list_entry(current, element_t, list); + list_del(current); + free(entry->value); + free(entry); + } - struct list_head *current = head->next; - while (current != head) { - struct list_head *temp = current; - current = current->next; - element_t *entry = (element_t *)((char *)temp - offsetof(element_t, list)); - list_del(temp); - free(entry->value); - free(entry); - } free(head); } ``` 之前也沒注意到有q_release_element()。 ```diff - free(entry->value); - free(entry); + q_release_element(entry); ``` ### q_insert_head // q_insert_tail 檢查節點是否存在會使得一定無法通過效能測驗,所以先刪除。 ```diff bool q_insert_head(struct list_head *head, char *s) { - if (!head || !s) { // Check if either head or s is NULL. - return false; - } element_t *new_element = malloc(sizeof(element_t)); if (!new_element) { return false; // Memory allocation failed for new_element. } new_element->value = strdup(s); // Duplicate the string. if (!new_element->value) { + free(new_element); // Free the allocated memory for new_element since - q_release_element // strdup failed. return false; } list_add(&new_element->list, head); // Insert the new element at the head of the list. return true; } ``` q_insert_tail 也移除檢測 ```diff bool q_insert_tail(struct list_head *head, char *s) { - if (!head || !s) { // Check if either head or s is NULL. - return false; - } ``` ### q_delete_mid 此題[2095. Delete the Middle Node of a Linked List](https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list/description/)我採用[快慢指針](https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.md)的方式 ```cpp bool q_delete_mid(struct list_head *head) { if (!head || list_empty(head) || list_is_singular(head)) return false; struct list_head *slow = head->next, *fast = head->next; struct list_head *prev = NULL; while (fast != head && fast->next != head) { prev = slow; slow = slow->next; fast = fast->next->next; } if (prev != NULL) { element_t *middle_element = list_entry(slow, element_t, list); list_del(slow); free(middle_element->value); free(middle_element); return true; } return false; } ``` ### q_delete_dup [82. Remove Duplicates from Sorted List II](https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/description/) ```c bool q_delete_dup(struct list_head *head) { if (!head || list_empty(head)) { return false; // Return false if the list is empty or head is NULL. } struct list_head *current = head->next, *next_node; bool global_deleted = false; bool duplicate_flag = false; while (current != head && current->next != head) { element_t *current_element = list_entry(current, element_t, list); next_node = current->next; // Move to the next node early because // current might get deleted. element_t *next_element = list_entry(next_node, element_t, list); // Check if current and next nodes have the same value. if (strcmp(current_element->value, next_element->value) == 0) { duplicate_flag = true; global_deleted = true; } // Move ahead to find the end of duplicates if there are any. while (duplicate_flag && next_node != head && strcmp(current_element->value, next_element->value) == 0) { struct list_head *temp = next_node->next; list_del(next_node); free(next_element->value); free(next_element); next_node = temp; // Proceed to next node. next_element = next_node != head ? list_entry(next_node, element_t, list) : NULL; } // If duplicates were found, delete the current node as well. if (duplicate_flag) { list_del(current); free(current_element->value); free(current_element); duplicate_flag = false; // Reset the flag for the next iteration. } current = next_node; // Proceed to next node for the next loop iteration. } return global_deleted; // Return true if any element was deleted. } ``` :::danger 針對環狀且雙向鏈結串列的特性,搭配 List API,撰寫出更精簡有效的程式碼。 ::: ### q_swap ### q_reverse ### q_reverseK ### q_sort 一開始採用插入排序法(Insertion sort),因為平均時間複雜度是$O(n^2)$,無法通過效能測驗。改用快速排序法(Quick Sort),平均複雜度是$O(n\log n)$但是沒注意到會測試最糟糕案例,因其最壞時間複雜度是$O(n^2)$無法通過。最後還是只能用最壞時間複雜度是$O(n\log{n})$的合併排序法 (Merge sort)處理。 :::danger 避免過多的中英文混用,已有明確翻譯詞彙者,例如「鏈結串列」(linked list) 和「佇列」(queue),就使用該中文詞彙,英文則留給變數名稱、人名,或者缺乏通用翻譯詞彙的場景。 ::: 在測驗時出現我的queue不是doubly linked list,後續才發現我的```*sortedMerge```沒有正確的連接好 :::danger 無論標題和內文中,中文和英文字元之間要有空白字元 (對排版和文字搜尋有利) ::: ### q_descend ### q_merge ## 研讀論文〈Dude, is my code constant time?〉 目前程式碼會有時95有時100,主因看來是這部份。目前是 q_insert_tail 與 q_insert_head 會出現 Probably not constant time or wrong implementation :::danger 無論標題和內文中,中文和英文字元之間要有空白字元 (對排版和文字搜尋有利) ::: ## Valgrind + 自動測試程式 ## 整合網頁伺服器 :::danger 段落中的程式碼標注,使用 1 個 [backtick](https://en.wikipedia.org/wiki/Backtick),而非 3 個。 ::: ## 實作```shuffle```命令 ## M03: ttt ###