# 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
###