# 2023q1 Homework1 (quiz1) contributed by < `DokiDokiPB` > ## 測驗 2 <s> ```c #include <stdint.h> #include "list.h" struct item { uint16_t i; struct list_head list; }; ``` ```c= #define MAX_DEPTH 512 static void list_sort_nr(struct list_head *head) { if (list_empty(head) || list_is_singular(head)) return; struct list_head stack[MAX_DEPTH]; for (int i = 0; i < MAX_DEPTH; i++) INIT_LIST_HEAD(&stack[i]); int top = -1; list_splice_init(head, &stack[++top]); struct list_head partition; INIT_LIST_HEAD(&partition); while (top >= 0) { INIT_LIST_HEAD(&partition); list_splice_init(&stack[top--], &partition); if (!list_empty(&partition) && !list_is_singular(&partition)) { struct list_head list_less, list_greater; INIT_LIST_HEAD(&list_less); INIT_LIST_HEAD(&list_greater); struct item *pivot = list_first_entry(&partition, struct item, list); list_del(&pivot->list); INIT_LIST_HEAD(&pivot->list); struct item *itm = NULL, *is = NULL; GGGG (itm, is, &partition, list) { list_del(&itm->list); if (cmpint(&itm->i, &pivot->i) < 0) list_move(&itm->list, &list_less); else list_move(&itm->list, &list_greater); } HHHH (&pivot->list, &list_less); if (!list_empty(&list_greater)) list_splice_tail(&list_greater, IIII); if (!list_empty(&list_less)) list_splice_tail(&list_less, JJJJ); } else { top++; list_splice_tail(&partition, &stack[top]); while (top >= 0 && list_is_singular(&stack[top])) { struct item *tmp = list_first_entry(&stack[top], struct item, list); list_del(&tmp->list); INIT_LIST_HEAD(KKKK); list_add_tail(&tmp->list, head); } } } } ``` 取 ```HHHH``` 為 ```list_splice_tail``` 取 ```GGGG``` 為 ```list_for_each_entry_safe``` 取 ```IIII``` 為 ```&stack[++top]``` 取 ```JJJJ``` 為 ```&stack[++top]``` 取 ```KKKK``` 為 ```&stack[top--]``` </s> :::danger 不用抄題目。闡述你的認知和想法。 :notes: jserv ::: #### 解釋程式碼原理 - 串列中的元素的排序取決於當前 while loop 的 ```partition``` 處理對象的順序,並且由 ```stack[top]``` 決定 - 在第 38 行中,依據 stack 的性質,```list_less``` 會是下一輪的 while loop 的 ```partition``` 處理對象。也就是會先處理最小值 - 最終當串列中元素數量小於等於 1 時,即表示此為當前最小值。 - 在 else case 中,將此串列的元素(僅有 1 個元素)加入至 ```head``` 末端中 <!-- 用 graphviz 繪製圖片有點麻煩 :) 使用 ASCIIFlow 網站繪製 :P https://asciiflow.com/ --> 以表格顯示過程 :::danger 使用 Graphviz 重製,並嵌入於 HackMD 頁面。 :notes: jserv ::: ``` 最一開始 stack 內容 +------+ | head | +------+ 第一次 while loop 後 --> +-------+ +-------+ +------+ | empty | | great | | less | +-------+ +-------+ +------+ top: 0 1 2 第二次 while loop 後 --> +-------+ +-------+ +-------+ +-------+ +------+ | empty | | empty | | great | | great | | less | +-------+ +-------+ +-------+ +-------+ +------+ top: 0 1 2 3 4 很多次 while loop 後 --> +----------+ +----------+ +----------+ | singular | | singular | | singular | +----------+ +----------+ +----------+ top: ... ... ... ``` #### 指出其缺失 參考上面表格的第二次 ```while loop``` 後,產生用不到的 ```empty```,```empty``` 的數量為($n$ 為節點數量) ,此不計算 ```singular``` 數量: $$ 2^0 + 2^1 + ... + 2^{(log_2{n}) - 1} \ = 2^{(log_2{n})} - 1 = n - 1 $$ 若 n = 256,```empty``` 的數量為 255 個,因此 ```MAX_DEPTH=512``` 實際能夠處理的節點數量少於 ```256``` 個 #### 比較和實驗 <!-- perf: https://hackmd.io/@sysprog/gnu-linux-dev/https%3A%2F%2Fhackmd.io%2Fs%2FB11109rdg --> #### 效能改進方案 - 特別是避免依賴 ```MAX_DEPTH```:可以先想到的就是將 ```MAX_DEPTH``` 替換為 ```head``` 的節點數量,並且在某些步驟時將 ```empty``` 移除,(或是 circular stack?) - 另一種偶然想到的方式, linked list 與 Array 混合版本,例如: ```c struct StackArray{ struct list_head chain; struct list_head stack[MAX_DEPTH]; } ``` <!-- 改進參考步驟 https://hackmd.io/@sysprog/c-linked-list#%E9%9D%9E%E9%81%9E%E8%BF%B4%E7%9A%84%E5%AF%A6%E4%BD%9C -->