# 2021q1 Homework1 (quiz1) contributed by < [Julian-Chu](https://github.com/Julian-Chu) > ###### tags: `linux2021` ## 程式處理流程 當 pointer to list 為 NULL 直接返回 ```cpp if(!*list) return; ``` 當 pointer to list 不為 NULL 繼續處理 ``` graphviz digraph structs { rankdir=LR node[shape=record] node3 [label="3"] node4 [label="4"] node1 [label="1"]; node2 [label="2"] node5 [label="5"] node3->node5 node5->node2 node2->node1 node1->node4 } ``` 與針對陣列操作的 quicksort 類似,先挑選基準點而後進行比較,這邊利用第一個 node 作為pivot , 同時把 pivot 與 next node 的連結切斷 ```cpp node_t *pivot = *list; int value = pivot->value; node_t *p = pivot->next; pivot->next = NULL; ``` ``` graphviz digraph structs { rankdir=LR node[shape=record] node3 [label="{<f0>pivot|<f1>3}"] node4 [label="4"] node1 [label="1"]; node2 [label="2"] node5 [label="5"] node3->node5[penwidth=0, arrowhead=none] node5->node2 node1->node4 node2->node1 } ``` 將其他的 node 與 pivot 比較分為兩群 left & right,大於 pivot 放在 right , 其餘放在 left ```cpp node_t *left = NULL, *right=NULL; while(p){ node_t *n = p; p = p->next; list_add_node_t(n->value > value ? &right : &left, n); } ``` ``` graphviz digraph structs { rankdir=LR node[shape=record] node3 [label="{<f0>pivot|<f1>3}"] node5 [label="{right|5}"] node2 [label="{left|2}"] node1 [label="1"] node4 [label="4"] node5->node4 node2->node1 {rankdir=BT;rank=same; node2, node3, node5} } ``` 對 left 跟 right,繼續處理,直到 left 跟 right 排好序 ```cpp quicksort(&left); quicksort(&right); ``` ``` graphviz digraph structs { rankdir=LR node[shape=record] node3 [label="{<f0>pivot|<f1>3}"] node4 [label="{right|4}"] node1 [label="{left|1}"] node2 [label="2"] node5 [label="5"] node4->node5 node1->node2 {rankdir=BT;rank=same; node1, node3, node4} } ``` 最後利用 left -> pivot -> right 的順序把 linked list 組合起來 ```cpp node_t *result = NULL; list_concat(&result, left); list_concat(&result, pivot); list_concat(&result, right); *list = result; ``` ``` graphviz digraph structs { rankdir=LR node[shape=record] node3 [label="{<f0>pivot|<f1>3}"] node4 [label="{right|4}"] node1 [label="{left|1}"] node2 [label="2"] node5 [label="5"] node4->node5 node1->node2 node2->node3 node3->node4 } ``` ### list_add_node_t 實作上的小差異可能導致 $O(1)$ 與 $O(n)$ 的巨大差異 題目的 list_add_node_t 為 $O(1)$ ```cpp static inline void list_add_node_t(node_t **list, node_t *node_t){ node_t->next = *list; *list = node_t; } ``` 如果實作細節是在 list 的 tail.next 加上節點的話,會導致每次都需要走訪 list 所有節點,導致這個函式的時間複雜度為 $O(n)$ ,由於 quicksort 在這一步只需要分成 left 和 right 兩部分, 不需要保持 left 跟 right 的位置或是插入順序 (quicksort 的 unstable 特性),`list_add_note_t` 效率更高。 :::warning todo: 閱讀 C11 對 inline 跟 static 的敘述 ::: ### Todo - random - non-recusive quicksort - linux circular doubly-linked list - A Comparative Study of Linked List Sorting Algorithms