Abel-Chu
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 2025q1 Homework1 (lab0) contributed by < `CodeStone1125` > ### Reviewed by `SimonLiu423` 1. `queue.h` 中已有 `q_release_element()` 函式可以去釋放指定的 element,為了增加可讀性及可維護性,建議將 `q_free()` 中釋放節點的部分改為利用這個函式達成。 2. > 另外也許可以結合 queue_contex_t 的使用在每次對佇列的操作都對 queue_contex_t.size 進行佇列長度的維護這樣的話呼叫 q_size 就直接回傳 queue_contex_t.size 即可。 考量到封裝性,`queue_contex_t` 有種將 queue 包起來的感覺,提供關於該 queue 的一些額外資訊,我想透過 queue 的基本操作獲取外部的 struct 資訊也許不是一個好的方法?歡迎其他人提供更多想法。 此外,考量到使用情況,若大部分時間只會對 queue 進行新增/移除元素,而不會詢問 queue 的大小,則會花費大量不必要的時間去更新 size 資訊。 3. Sorting Methods Comparison 的圖表中,X 軸的單位建議可以以 $10^3$(k) 為單位,顯示的數值便可從 $100000$, $200000$, ... 變成 $100$, $200$, ...,增加圖表的可讀性。 ### Reviewed by `NeedToDebugMyLife` 1. Commit [25c014d](https://github.com/sysprog21/lab0-c/commit/25c014daeb2f889c9e72f7368d73f42edc4574e2) 中,可以使用 `!head` 的寫法來替代 `head==NULL`,這樣的寫法更為精簡,`head->next == head` 的寫法可以使用 `<list.h>` 中的 `list_empty()` 來替代。 2. Commit [467decc](https://github.com/sysprog21/lab0-c/commit/467decc5a599d1f4a984eeaab6d3dfd66ea114fc) 中,可以透過將節點 "移除後再插入" 的方式完成節點的搬動,這邊可以直接使用 `<list.h>` 中的 `list_del()` 和 `list_add()` 這兩個巨集函式來完成,或者直接使用 `<list.h>` 中的 `list_move()`,這樣可以有效提高程式碼的可讀性。 {%hackmd NrmQUGbRQWemgwPfhzXj6g %} ## 開發環境 ```shell $ gcc --version gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 $ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 46 bits physical, 48 bits virtual CPU(s): 28 On-line CPU(s) list: 0-27 Thread(s) per core: 2 Core(s) per socket: 20 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 183 Model name: Intel(R) Core(TM) i7-14700 @ 1.50 GHz Stepping: 1 CPU MHz: 1100.3190 CPU max MHz: 5400.0000 CPU min MHz: 800.0000 BogoMIPS: 4224.00 Virtualization: VT-x L1d cache: 768 KiB L1i cache: 1 MiB L2 cache: 28 MiB L3 cache: 33 MiB NUMA node0 CPU(s): 0-27 ``` ## 教材閱讀 - [x] [你所不知道的 C 語言:指標篇](https://hackmd.io/@sysprog/c-linked-list) - [x] [你所不知道的 C 語言: linked list 和非連續記憶體](https://hackmd.io/@sysprog/c-linked-list) - [x] [你所不知道的 C 語言:記憶體管理、對齊及硬體特性](https://hackmd.io/@sysprog/c-memory) - [x] [list_sort.c](https://github.com/torvalds/linux/blob/master/lib/list_sort.c) - [ ] [Linux 核心的 hash table 實作](https://hackmd.io/@sysprog/linux-hashtable) ## 佇列操作的程式碼實作 ### q_new > Commit [8a99fa7](https://github.com/sysprog21/lab0-c/commit/8a99fa70e8a3be4825058d84fb8b12603322727e) 使用 `malloc` 避免物件的生命週期隨著 `q_new` 一起結束。 > Commit [999800f](https://github.com/sysprog21/lab0-c/commit/999800f9fbdb0c2638afa8a530c94cdd0009c90e) 研讀 `list.h` 後使用 `INIT_LIST_HEAD` 簡化程式。 ### q_free 最一開始構思的程式碼有以下問題: 1. 沒有仔細研讀 `qtest.c` 導致沒有發現不需要在函式中釋放 `queue_contex_t` 的記憶體。 2. 誤用 `list_for_each` 而非 `list_for_each_safe` 導致 segemnt fault。 修正後版本: > Commit [e07f9bb](https://github.com/sysprog21/lab0-c/commit/e07f9bba950e44dda16d5491d36173b41bc4a71e) ```c void q_free(struct list_head *head) { if (head == NULL) return; struct list_head *node; struct list_head *safe; list_for_each_safe (node, safe, head) { element_t *e_new = list_entry(node, element_t, list); if (e_new->value) free(e_new->value); free(e_new); } free(head); return; } ``` ### q_size > Commit [25c014d](https://github.com/sysprog21/lab0-c/commit/25c014daeb2f889c9e72f7368d73f42edc4574e2) 我使用了 `list_for_each_safe` 走訪佇列的每一個元素並計算佇列長度但因為操作沒有涉及元素的刪除應該使用 `list_for_each` 即可可以省下一半的走訪成本。 另外也許可以結合 `queue_contex_t` 的使用在每次對佇列的操作都對 `queue_contex_t.size` 進行佇列長度的維護這樣的話呼叫 `q_size` 就直接回傳 `queue_contex_t.size` 即可。 ### q_del_mid > Commit [55147bf](https://github.com/sysprog21/lab0-c/commit/55147bfb01df095ab8a43017c1c38d60fd322c82) 參考指標篇的快慢指標實作 `q_del_mid`,值得注意的是 `slow` & `fast` 指標的起始點從 `head` 或是 `head->next` 結果是一樣的,因為已經設定了只要佇列長度小於1就不會進入迴圈計算而在佇列長度大於等於2的情況下兩者結果一樣,但是 `head->next` 可以減少一次迴圈次數所以我認為是更優異的選擇。 ```c struct list_head * slow = head->next; for(struct list_head * fast = head->next; fast->next!=head && fast->next->next!=head; fast=fast->next->next){ slow = slow->next; } ``` > Commit [5afc936](https://github.com/sysprog21/lab0-c/commit/5afc936b7bd41ca15b82dee09cdbf16bbb75e0c1) 這個提交修正了初版沒有手動釋放包含 `mid` 的元素記憶體空間,導致的記憶體洩漏。 ```diff + element_t *e = list_entry(slow, element_t, list); + free(e->value); + free(e); ``` ### q_insert_head & q_insert_tail > q_insert_head:Commit [4a12cd0](https://github.com/sysprog21/lab0-c/commit/4a12cd04b49a7d4c4ef81fec8cb86bb212ba7a83) > q_insert_tail:Commit [879b201](https://github.com/sysprog21/lab0-c/commit/879b201464dd13df0008204a13790ae6d7edd5a5) > 插入在開頭和結尾的邏輯類似,差別在於只在於透過開頭的 `->prev` 存取結尾來操作。並且二者都要針對當前佇列是否為空做處理。 ```diff + element_t *e_new = (element_t *)malloc(sizeof(element_t)); + e_new->value = (char *)malloc(sizeof(char)*(1+strlen(s))); ``` 使用 `malloc` 分配記憶體空間到堆積避免插入的 `element_t` 及其中的物件生命週期隨著函式結束終止產生 `dangling pointer` 問題。 `malloc` 回傳的 `void *` 是不可以直接進行物件存取,要透過強制轉型成適配的資料型態以作進一步操作。 > Dangerous function detected in strcpy(e_new->value, s); > Read 'Common vulnerabilities guide for C programmers' carefully. 針對 `strcpy` 導致可能發生的溢位問題使用 `strlcpy` 限制使用的記憶體位址範圍防範。 ### q_remove_head & q_remove_tail > q_remove_head:Commit [5ad38c7](https://github.com/sysprog21/lab0-c/commit/5ad38c74582044d7abc519495f233dd160a5f12c) > q_remove_tail::Commit [16be85b](https://github.com/sysprog21/lab0-c/commit/16be85b7160213611959ae0480ebc508304148a6) 需要注意的點和實作邏輯和 [q_insert_head & q_insert_tail](https://hackmd.io/gKRaBCWZR3abBEfS8jBlLg#q_insert_head-%EF%BC%86-q_insert_tail) 類似故不贅述。 > Commit [4070736](https://github.com/sysprog21/lab0-c/commit/4070736a2c77dbb91e0c9cf4cac8347f5ea0131a) 這次提交修正了對於 `strlcpy` 理解不完全輸入錯誤的參數導致的無法通過 `truncated strings` 的測試。 ### q_ascend & q_descend > Commit [e43716f](https://github.com/sysprog21/lab0-c/commit/e43716f8ad078685e95019a074ca2f5bd5126888) `q_ascend` 和 `q_descend` 的實作邏輯類似 1. 利用堆疊儲存元素 2. 當下在堆疊頂端的元素嚴格大於(小於)當下的檢查的元素 3. 直到堆疊頂端不再嚴格大於(小於)當下的檢查的元素 4. 將堆疊的結果放回佇列中並釋放堆疊 ### q_reverseK & q_reverse > q_reverseK:Commit [5937720](https://github.com/sysprog21/lab0-c/commit/59377209931db7bb8ecdf97ac53470800e36841e8) > q_reverse:Commit [904be06](https://github.com/sysprog21/lab0-c/commit/904be06ca15c34bcaceca54fee4374c23233b0c6) `q_reverseK` 的做法利用兩個指標 `start` 和 `end`: 用 while 迴圈走訪整個佇列,`start` 和 `end` 放在第一個元素並且 `end` 持續走訪佇列每當 `end` 向前走訪 K-1 個元素則用另一個 `tmp` 搭配 `list_add_tail` 反轉佇列在放回原本的佇列中。 此外我的 `q_reverse` 是 `q_reverseK` 的特例 `q_size == K` ### q_delete_dup > Commit [672cee2](https://github.com/sysprog21/lab0-c/commit/672cee2b21ce8b65d8708d7469648f0072b05ad7) 首先我的想法是: 1. 利用 `q_sort` 將所有重複的元素排序在一起 2. 使用 `list_for_each_safe` 走訪所有元素 3. 兩兩比較確認是否有的重複元素,利用 `dup` 記錄當前的元素是否和下一個元素重複, - 如果重複,刪除當前的元素`dup` 改成 true。 - 如果沒有重複則把當下元素加入 `tmp` 暫時存放。 4. 當 `dup == true` 時可以知道當前的元素是重複的(即使當下兩兩比較的元素不同),因此刪除當前的元素並將 `dup` 改回 false。 5. 最後把 `tmp` 中不重複元素放回原本的佇列。 ### q_swap > Commit [467decc](https://github.com/sysprog21/lab0-c/commit/467decc5a599d1f4a984eeaab6d3dfd66ea114fc) 在迴圈中每兩個一組 `<first, second>` 的進行交換,每一次迴圈 `first` 指標指向下兩個元素並且將 `swp_tmp` 指向 `second` 進行元素的刪除和加入,此處應可用 `list_del_init` 簡化程式碼。 ```diff swp_tmp->next = first; first->prev = swp_tmp; + first = first->next; - first = first->next->next; ``` 另外,測試結果中發現我使用交換的方式,並且交換完後使用 `first->next->next` 存取下一對元素會出現錯誤,因為 `first` 經過交換後實際上只需要使用 `first->next` 即可存取到下一對元素的 `first`。 以下是錯誤更正前的執行結果: ``` l = [a b c d e f] cmd> swap l = [b a c e d f] ``` ### q_sort > Commit [a14ee65](https://github.com/sysprog21/lab0-c/commit/a14ee65c6c7887d62a23f9a58765330869d78ea7) ![image](https://hackmd.io/_uploads/SJMDaBdjkx.png) 這個提交是我實作的 stable 的 `merge sort` ,利用遞迴版本 `q_sort` 切割佇列元素,並且用 `mergeTwoList(left, right)` 排序並結合分為兩種情況: 1. `left`, `right` 都非空及 `NULL` 2. 兩者其中一個是空或 `NULL` 情況1.需要分別比較兩者的最小元素比較小的元素來做合併,並重複比較直到情況2.後直接將剩餘的元素合併進入結果即可: - 參考了 [lib/list_sort.c](https://hackmd.io/@sysprog/linux2025-lab0/%2F%40sysprog%2Flinux2025-lab0-f%3Fstext%3D1546%253A80%253A0%253A1741344947%253AJ_nGlo) 利用 `strcmp >= 0` 來保證排序的穩定性 #### Segment Fault 我原本的思路是在 `mergeTwoList` 使用額外建立 `result` 儲存合併結果在情況2.後直接將剩餘的元素合併進入 `result` 並回傳。但是 `result` 是在 `mergeTwoList` 中建立的,物件的生命週期和函式運行週期綁定,所以回傳後再去存取 `result` 就會導致 Segment Fault。 ```diff if (!list_empty(left)) { - list_splice(left, &result); - return &result; + list_splice(&, left); + return left; } else { - list_splice(right, &result); - return &result; + list_splice(&result, right); + return right; } ``` 參考了 [alexc-313](https://hackmd.io/@alex-c1234/linux2025-homework1#q_sort) 情況2.的做法將 `result` 利用 `list_splice` 加入 `left` 或 `right`並回傳,我認爲使用指標的指標可以進一步把回傳值的部分移除。 ### q_merge 觀察 `qtest.c` 發現整體架構中有四種物件: - list_head:實際用來管理佇列的物件 - element_t:用於儲存佇列中的元素 - queue_context_t:用於鏈結和統計單一佇列資訊 - queue_chain_t:用於鏈結和統計所有佇列資訊 > Commit [324ef82](https://github.com/sysprog21/lab0-c/commit/324ef82dda4073dacef1d5f51dda82ab6fb547e0) `q_merge` 需要存取及管理到 `queue_chain_t` 和 `queue_context_t` 的部分。我目前的做法將每一輪都拿第一個佇列來做 `mergeTwoList`,導致第一個佇列的元素數特別多又做了很多次額外比較操作,如果能把這部分也改成 buttom-up 最後再把結果合併到第一個佇列應該可以提高效能。 此外這個做法有一些記憶體洩漏問題沒有被解決依據 `queue.h` 需求必須把第一個佇列以外的佇列變成 NULL-queue 但是直接將佇列變成 NULL-queue 卻沒有初始化 `list_head` 會導致記憶體洩漏,因為不知道指標會指向哪裡。但在此同時直接在函式中呼叫 `free()` 釋放記憶體又是不被允許的,我有嘗試過將變成 NULL-queue 後呼叫 `INIT_LIST_HEAD` 或反過來的做法都會導致 Segment Fault,但不正確初始化會導致後續 `list_head` 的釋放出現記憶體洩漏,我目前還沒有找到解法先做紀錄。 ```diff ctx->q = NULL; + INIT_LIST_HEAD(ctx->q); ``` > Commit [4b0a9be](https://github.com/sysprog21/lab0-c/commit/4b0a9be414bdcb0a87f40c4e938a3ed00247dcc3) 參考 [allen741](https://hackmd.io/@wMTPWBL3SY-hXZO6zn-QmQ/ryamiY6cJx#q_merge) 的做法利用 `list_splice_init` 將所有佇列的元素移到第一個佇列再做 `q_sort`,這方法可以順利初始化並避免記憶體洩漏但是會導致已經排序過的序列再次排序造成額外的比較次數,這方法就算所有序列都沒有排序過也是用算是一個更廣泛的解法,但`list_splice_init` 的方式避免了 `mergeTwoList` 不同佇列間的元素比較,哪個方法比較好要透過實際的效能測量確定。 ## 研讀 [lib/list_sort.c](https://github.com/torvalds/linux/blob/master/lib/list_sort.c#L13) ### 研讀 Linux 核心原始程式碼 **施工中** ### 嘗試引入 `list_sort.c` 到 lab0-c 專案 > Commit [93c6190](https://github.com/CodeStone1125/lab0-c/commit/93c6190494fc48fbe7530b80171bf393798d71f6) #### 修改 `list_sort.c` 我參考 [kart81604](https://hackmd.io/@kart81604/HkGHY1cTs#%E5%B0%87-liblist_sort-%E5%BC%95%E5%85%A5%E8%87%B3-lab0-c-%E5%B0%88%E6%A1%88) 的做法嘗試引入linux核心風格的程式碼到 lab-0-c: ```c // original version __attribute__((nonnull(2,3,4))) static struct list_head *merge(void *priv, list_cmp_func_t cmp, struct list_head *a, struct list_head *b); __attribute__((nonnull(2,3,4,5))) static void merge_final(void *priv, list_cmp_func_t cmp, struct list_head *head, struct list_head *a, struct list_head *b); __attribute__((nonnull(2,3))) void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp); ``` 為了引入這段程式碼我做了以下改寫: 1. 我移除了一些額外的部分像 `priv` `like` 和 `unlike` `__attribute__`, 2. 把 `merge`,`merge_final`,`list_sort` 加上前綴 `lx_` 方便識別 3. 把 `cmp` 用 `strcmp` 代替 ```c static struct list_head *lx_merge(struct list_head *a, struct list_head *b); static void lx_merge_final(struct list_head *head, struct list_head *a, struct list_head *b); void lx_list_sort(struct list_head *head); ``` 針對我做了以上改變後遇到執行 `lx_sort` 遇到 `segment fault`,透過`debug.py` 訊息發現問題出在 439 行因為我在取得 `element_t` 物件時 錯誤使用成 `list_first_entry` 而非 `list_entry` 導致。 ```python Program received signal SIGSEGV, Segmentation fault. 0x000055555555c14d in lx_merge (a=a@entry=0x55555556a708, b=0x55555556a678) at queue.c:439 439 if (strcmp(e_a->value, e_b->value) <= 0) { ``` ```diff - element_t *e_a = list_first_entry(a, element_t, list); - element_t *e_b = list_first_entry(b, element_t, list); + element_t *e_a = list_entry(a, element_t, list) + element_t *e_b = list_entry(b, element_t, list)->value) if (strcmp(e_a->value, e_b->value) <= 0) ``` #### 為 `qtest.c` 添加指令 > Commit [fd00b86](https://github.com/CodeStone1125/lab0-c/commit/fd00b86e22e98aada39ebf1b6c7e9981f4219ca7) 為了可以在 `qtest.c` 呼叫 `c_sort` 必須為 `qtest.c` 添加指令 `c_sort` 功能並透過選項控制使用的排序演算法。 ```c /* Get sorting method */ const char *sort_method = argv[1]; ... if (strcmp(sort_method, "-l") == 0) { lx_sort(current->q); } else if (strcmp(sort_method, "-s") == 0) { sediment_sort(current->q); } else if (strcmp(sort_method, "-t") == 0) { tree_sort(current->q); } else { report(1, "Invalid sorting method: %s", sort_method); return false; } ``` 以下是呼叫範例: ``` l = [dlagrm kxuimm crecsp zqzde xczea oecvj thhbki gtiji jiuauin tlldmszei] cmd> c_sort -t // -t for treesort l = [crecsp dlagrm gtiji jiuauin kxuimm oecvj thhbki tlldmszei xczea zqzde] ``` 在 `console_init` 中加入後就可以在 `qtest.c` 中呼叫 `lx_sort` 並且呼叫後 `qtest.c` 會啟動 `do_lx_sort` ,這部分我直接複製 `do_sort` 並把 `q_sort` 改成 `lx_sort`。 ```c #define ADD_COMMAND(cmd, msg, param) add_cmd(#cmd, do_##cmd, msg, param) ADD_COMMAND(c_sort, "Various sorting queue methods, -t:tree_sort, -s:sediment_sort " ", -m:lx_sort", ""); ``` - `queue.h` 不能修改? 針對 `queue.h` 不能修改但是 `qtest.c` 需要從 `queue.h` 引入的解決辦法可以在 `qtest.c` 中 `#include "queue.h"` 的後面下一行(或更多行)宣告: ```diff + void lx_sort(struct list_head *head); ``` ---- ### 環狀雙向鏈結串列的排序效能比較 > 將程式碼整合進 lab0 提及的 qtest,並探討環狀雙向鏈結串列的排序效能,並善用 perf 一類的效能分析工具,探討包含 Linux 核心 list_sort 在內排序實作的效能表現並充分解釋 > Commit [c59ebc6](https://github.com/sysprog21/lab0-c/commit/c59ebc61d778a90c81bc88840ce719be92637998) 參考 [2025q1 第 2 週測驗 1](https://hackmd.io/@sysprog/linux2025-quiz2#%E6%B8%AC%E9%A9%97-1) 穩定排序版的快速排序將程式碼整合進 [lab0](https://hackmd.io/@sysprog/linux2025-lab0) 提及的 `qtest` 將 `listitem` 改成 `element_t` 並稍微改變參數名稱和函式名即可。 > Commit [51db328](https://github.com/sysprog21/lab0-c/commit/51db328184ecb398460a68cdc8815fd5207d51b7) 先實作了一個 `sort_perf.bash` 使用 `perf` 測量不同排序法的不同指標,並且使用 `gnuplot` 畫圖片 以下是測量長度十萬到一百萬的排序延遲時間: ![sort_comparison](https://hackmd.io/_uploads/SkO6op4hJl.png) - `Tree sort` 和 `Quick sort` 雖然是 `O(NlogN)` 的演算法但是隨著鏈結串列長度增加延遲大幅上升逼近甚至超過 `Sediment Sort` - **`Tree sort` 推測時間來自 `top-down` 建立二元搜尋數** - **`Quick sort` 推測來自大量的指標和陣列管理** - Linux 核心的 `List sort` 在不論鏈結串列長度幾乎都是最佳選擇 - 排除 `List sort` 的話 `Sediment Sort` 雖在鏈結串列長度短的很慢但表現穩定在很長的鏈結串列長度是比 `Tree sort` 和 `Quick sort` 更快的選擇。 ### 嘗試改進針對鏈結串列排序實作的效能 **施工中** --- ## 在 `qtest` 提供新的命令 `shuffle` > Commit [e09e4cf](https://github.com/CodeStone1125/lab0-c/commit/e09e4cf27ce477e965250d530674da88df3e704c) ### Fisher–Yates shuffle 實作 以下是我利用 Fisher–Yates shuffle 演算法實作 `shuffle`: 針對以下 1.~2.要重複運行 `N - 1` 次,N 取自佇列的尺寸 `q_size` 1. 從前面第 1 ~ `q_size - iteration` 個元素中隨機挑選一個元素 `R` 2. 將`R` 插入佇列尾端 我透過以上想法實作 `shuffle` 並且在 `qtest.c` 加入`do_shuffle` ### 統計的原理來分析洗牌「亂度」 ``` Expectation: 4166 Observation: {'1234': 4166, '1243': 4180, '1324': 4234, '1342': 4327, '1423': 4251, '1432': 4173, '2134': 4186, '2143': 4113, '2314': 4142, '2341': 4173, '2413': 4209, '2431': 4223, '3124': 4168, '3142': 4183, '3214': 4174, '3241': 4180, '3412': 4061, '3421': 4072, '4123': 4183, '4132': 4053, '4213': 4166, '4231': 4163, '4312': 4107, '4321': 4096} chi square sum: 21.31757081132981 ``` 這是測試 100000次的結果: || 觀察到的頻率 | 期待的頻率 | ${(O_i - E_i)^2 \over E_i}$ | | -------- | -------- | -------- | --- | | [1, 2, 3] | 166391 | 166666 | 0.45375181500726003 | | [2, 1, 3] | 166829 | 166666 | 0.15941463765855063 | | [2, 3, 1] | 166807 | 166666 | 0.11928647714590858 | | [1, 3, 2] | 166790 | 166666 | 0.0922563690254761 | | [3, 1, 2] | 166862 | 166666 | 0.23049692198768795 | | [3, 2, 1] | 166321 | 166666 | 0.7141528566114265 | | Total | | | 1.76935907743631 | 從[卡方分布表](https://en.wikipedia.org/wiki/Chi-squared_distribution)找合適的 P value,我們的自由度為 23,$X^2$ 為 21.31757081132981,因為 21.31757081132981 < 32.007,於是 P value 大於 0.1 。 | df | 0.995 | 0.99 | 0.975 | 0.95 | 0.90 | 0.10 | 0.05 | 0.025 | 0.01 | 0.005 | | --- | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | 20 | 7.434 | 8.260 | 9.591 | 10.851 | 12.443 | 28.412 | 31.410 | 34.170 | 37.566 | 39.997 | | 21 | 8.034 | 8.897 | 10.283 | 11.591 | 13.240 | 29.615 | 32.671 | 35.479 | 38.932 | 41.401 | | 22 | 8.643 | 9.542 | 10.982 | 12.338 | 14.041 | 30.813 | 33.924 | 36.781 | 40.289 | 42.796 | | 23 | 9.260 | 10.196 | 11.689 | 13.091 | **14.848** | **32.007** | 35.172 | 38.076 | 41.638 | 44.181 | | 24 | 9.886 | 10.856 | 12.401 | 13.848 | 15.659 | 33.196 | 36.415 | 39.364 | 42.980 | 45.559 | | 25 | 10.520 | 11.524 | 13.120 | 14.611 | 16.473 | 34.382 | 37.652 | 40.646 | 44.314 | 46.928 | 因為 P value(>0.1)> alpha(0.05),統計檢定的結果不拒絕虛無假說($H_0$) 也就是樣本資料不拒絕 shuffle 的結果遵循 Uniform distribution。 ![shuffle](https://hackmd.io/_uploads/B1PPcKV2Jg.png)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully