# 2021q1 Homework1 (quiz1) contributed by < `ngokchaoho` > > [2021q1 第 1 週測驗題](https://hackmd.io/@sysprog/linux2021-quiz1) ## 程式運作原理 ### `list_add_node_t` 加新的節點到 list 開頭 ```cpp static inline void list_add_node_t(node_t **list, node_t *node_t) { node_t->next = *list; *list = node_t; } ``` * 這裡使用到了 pointer to pointer 的技巧,`*list` 指向 head (e.g. A) `list_add_node_t 前` ```graphviz digraph graphname{ "*list"[shape=plaintext,fontcolor=red] list[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=A] B[label=B] C[label=C] D[label=note_t] NULL1[label=NULL,shape=plaintext] NULL2[label=NULL,shape=plaintext] } { rank="same"; list[shape=plaintext,fontcolor=blue] list->"*list"->A } A->B->C->NULL1 D->NULL2 } ``` `list_add_node_t 後` ```graphviz digraph graphname{ "*list"[shape=plaintext,fontcolor=red] list[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=A] B[label=B] C[label=C] D[label=note_t] NULL1[label=NULL,shape=plaintext] } { rank="same"; list[shape=plaintext,fontcolor=blue] list->"*list"->D } D->A->B->C->NULL1 } ``` ### `list_concat` 合併兩個 list ```c++ static inline void list_concat(node_t **left, node_t *right) { while (*left) left = &((*left)->next) *left = right; } ``` #### before: ```graphviz digraph graphname{ "*left"[shape=plaintext,fontcolor=red] left[shape=plaintext,fontcolor=blue] right[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=A] B[label=B] C[label=C] D[label=D] E[label=E] F[label=F] NULL1[label=NULL,shape=plaintext] NULL2[label=NULL,shape=plaintext] } { rank="same"; left[shape=plaintext,fontcolor=blue] left->"*left"->A right[shape=plaintext,fontcolor=blue] right->D } A->B->C->NULL1 D->E->F->NULL2 } ``` #### in the middle: travel through left list, `left = &((*left)->next)` ```graphviz digraph graphname{ "*left"[shape=plaintext,fontcolor=red] left[shape=plaintext,fontcolor=blue] "(*left)->next"[shape=plaintext,fontcolor=red] rankdir=LR { rankdir = LR A[label=A] B[label=B] C[label=C] NULL1[label=NULL,shape=plaintext] } { rank="same"; left[shape=plaintext,fontcolor=blue] left->"*left"->A "(*left)->next"->B } A->B->C->NULL1 } ``` ```graphviz digraph graphname{ left[shape=plaintext,fontcolor=blue] "(*left)->next"[shape=plaintext,fontcolor=red] rankdir=LR { rankdir = LR A[label=A] B[label=B] C[label=C] NULL1[label=NULL,shape=plaintext] } { rank="same"; left->"(*left)->next"->B } A->B->C->NULL1 } ``` until ```graphviz digraph graphname{ "*left"[shape=plaintext,fontcolor=red] left[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=A] B[label=B] C[label=C] NULL1[label=NULL,shape=plaintext] } { rank="same"; left[shape=plaintext,fontcolor=blue] left->"*left"->NULL1 } A->B->C->NULL1 } ``` and now change what C is pointing (represented by `*left`) to `right` i.e. the address of D #### after: ```graphviz digraph graphname{ "*left"[shape=plaintext,fontcolor=red] left[shape=plaintext,fontcolor=blue] right[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=A] B[label=B] C[label=C] D[label=D] E[label=E] F[label=F] NULL2[label=NULL,shape=plaintext] } { rank="same"; left[shape=plaintext,fontcolor=blue] left->"*left"->D right[shape=plaintext,fontcolor=blue] right->D } A->B->C->D->E->F->NULL2 } ``` ### quick sort 主要邏輯 ```c++ void quicksort(node_t **list) { if (!*list) return; node_t *pivot = *list; int value = pivot->value; node_t *p = pivot->next; pivot->next = NULL; 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); } quicksort(&left); quicksort(&right); node_t *result = NULL; list_concat(&result, left); list_concat(&result, pivot); list_concat(&result, right) *list = result; } ``` - 如果` *list ` 指向 NULL則結束,沒有需要排序 - 否則將鏈表的開頭 pivot 割出,初始化 p 為第二個node, 並用 p 遍歷 list - 將每一個 p 指向的 node 與 pivot 指向的 node 的 value 比較,建立嚴格比 ` pivot->value ` 小的 left list 和嚴格比嚴格比 `pivot->value`大的 right list. - 對 left list 同 right list 分別 quicksort 引發遞迴,結束條件為 NULL - 返回後, left list 同 right list 都是有序 list, 不斷從左往右加上更大的sublist - 回傳 result #### start: ```graphviz digraph graphname{ "p"[shape=plaintext,fontcolor=red] "pivot"[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=5] B[label=6] C[label=3] D[label=1] E[label=2] F[label=0] NULL2[label=NULL,shape=plaintext] NULL3[label=NULL,shape=plaintext] } { rank="same"; "p"->B "pivot"->A } A->NULL3 B->C->D->E->F->NULL2 } ``` #### split: ```graphviz digraph graphname{ "pivot"[shape=plaintext,fontcolor=blue] "left"[shape=plaintext,fontcolor=blue] "right"[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=5] B[label=6] C[label=3] D[label=1] E[label=2] F[label=0] NULL1[label=NULL,shape=plaintext] NULL2[label=NULL,shape=plaintext] NULL3[label=NULL,shape=plaintext] } { rank="same"; "pivot"->A "left"->C "right"->B } C->D->E->F->NULL1 B->NULL2 A->NULL3 } ``` #### after further recursive quicksort: ```graphviz digraph graphname{ "pivot"[shape=plaintext,fontcolor=blue] "left"[shape=plaintext,fontcolor=blue] "right"[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=5] B[label=6] C[label=3] D[label=1] E[label=2] F[label=0] NULL1[label=NULL,shape=plaintext] NULL2[label=NULL,shape=plaintext] NULL3[label=NULL,shape=plaintext] } { rank="same"; "pivot"->A "left"->F "right"->B } F->D->E->C->NULL1 B->NULL2 A->NULL3 } ``` #### concat: ```graphviz digraph graphname{ "pivot"[shape=plaintext,fontcolor=blue] "left"[shape=plaintext,fontcolor=blue] "right"[shape=plaintext,fontcolor=blue] "result"[shape=plaintext,fontcolor=blue] rankdir=LR { rankdir = LR A[label=5] B[label=6] C[label=3] D[label=1] E[label=2] F[label=0] NULL1[label=NULL,shape=plaintext] } { rank="same"; "pivot"->A "left"->F "result"->F "right"->B } F->D->E->C->A->B->NULL1 pivot } ```