# 2020q3 Homework1 (quiz1) contributed by < `sammer1107` > ###### tags: `進階電腦系統理論與實作` [TOC] ## AA1 & AA2 ```cpp=9 void add_entry(node_t **head, int new_value) { node_t **indirect = head; node_t *new_node = malloc(sizeof(node_t)); new_node->value = new_value; new_node->next = NULL; AA1; while (*indirect) indirect = &(*indirect)->next; AA2; } ``` ### 程式理解 1. 13~15 行的地方我們已經要了新的記憶體,並在上面放入了新的值 2. 18~19 行的目的是要找到最後一個節點(當 next 為 NULL) ### AA1 根據上面的理解,**AA1** 不應該是 ```*indirect = new_node```,否則迴圈執行的結果永遠都是得到 NULL 後結束。因此 **AA1** 應是 assert(new_node),檢查是否正確取得記憶體。 ### AA2 找到最後一個節點後,需要將最後的 `next` 指標指向 `new_node`。迴圈結束時,`*indirect`相當於最後一個節點的 `next` ,故答案為 `*indirect = new_node`。 ## BB1 & BB2 ```c=42 node_t *swap_pair(node_t *head) { for (node_t **node = &head; *node && (*node)->next; BB1) { node_t *tmp = *node; BB2; tmp->next = (*node)->next; (*node)->next = tmp; } return head; } ``` ### BB1 1. `swap_pair` 的功能為兩兩掉換,故 **BB1** 的功能是要連跳兩個 node。 3. 而且這裡我們是要改變 node 指向的位置而不是要修改 List 連接,故等號左邊要是 `node` 而不是 `*node`。 4. (a) 不對因為 `next` 的 type 為 `node_t*` ,故要再取址才是我們要的。 答案為 `(e) node = &(*node)->next->next` ### BB2 1. 在迴圈內我們要完成交換 Node 的工作,經過第 4 行後 ```c=45 node_t *tmp = *node; ``` 指標們長這樣,node1 與 node2 為目前要 swap 的節點。... 則代表前後延伸的節點 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] nodepp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">node</TD></TR> </TABLE>>]; tmpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">tmp</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node1</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> b:val; b:next:c -> c:val; c:next:c -> d:val; { rank=same; nodepp:p:s -> a:next:c; } { rank=same; tmpp:p:s -> b:val; } } ``` :::warning 這樣表示 `node` 為指向前一節點的 `next` 的指標,`tmp` 則為指向第1節點的指標。 ::: 2. 要把 node2 往前移的第一個動作就是把前一個節點的 `next` 牽往 node2。==做完後==長這樣 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] nodepp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">node</TD></TR> </TABLE>>]; tmpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">tmp</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node1</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> b:val [style=invis] a:next:c -> c:val; b:next:c -> c:val; c:next:c -> d:val; { rank=same; nodepp:p:s -> a:next:c; } { rank=same; tmpp:p:s -> b:val; } } ``` 這裡我們要修改的是前一個 node 的 `next` 讓他指向 node2 ,故等號左邊應是 `*node`,而 node2 的位置為 `(*node)->next` (等於 node1 的 `next` )。故答案選 **(e)** 3. 下一行將後面的節點交手從 node2 交手給 node1。 ```c=47 tmp->next = (*node)->next; ``` 做完後長這樣 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] nodepp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">node</TD></TR> </TABLE>>]; tmpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">tmp</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node1</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c -> b [style=invis]; a -> b [style=invis]; a:next:c -> c:val; b:next:c -> d:val; c:next:c -> d:val; { rank=same; nodepp:p:s -> a:next:c; } { rank=same; tmpp:p:s -> b:val; } } ``` 4. 最後將 node1 接在 node2 後面就完成了 ```c=48 (*node)->next = tmp; ``` 完成圖 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] nodepp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">node</TD></TR> </TABLE>>]; tmpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">tmp</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node1</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> c:val; b:next:c -> d:val; c:next:c -> b:val; { rank=same; nodepp:p:s -> a:next:c; } { rank=same; tmpp:p:s -> b:val; } } ``` ## CCC ```c=53 node_t *reverse(node_t *head) { node_t *cursor = NULL; while (head) { node_t *next = head->next; CCC; head = next; } return cursor; } ``` 要 reverse linked list 我們需要兩個指標一前一後走到底,而 `cursor` 在這裡就是跟在 `head` 之後的指標。故選項要選 **(b)**`head->next = cursor; cursor = head` ,把 `head` 的 `next` 改為指向前一個節點,然後 `cursor` 和 `head` 各往前走一步。 ### 第1次進迴圈的情況(57行) ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] head [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node1 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; cursor [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">cursor</TD></TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR><TD PORT="p">NULL</TD></TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node4 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; next [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">next</TD></TR> </TABLE>>]; a:next:c -> b:val; b:next:c -> c:val; c:next:c -> d:val; { rank=same; cursor:p:s -> null:n; } { rank=same; head:p:s -> a:val; } { rank=same; next:p:s -> b:val; } null -> a [style=invis] } ``` 做完 `head->next = cursor` 後 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] head [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> node1 </TD> </TR> </TABLE>>]; cursor [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">cursor</TD></TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR><TD PORT="p">NULL</TD></TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node4 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; next [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">next</TD></TR> </TABLE>>]; null:p:e -> a:next:c [dir=back]; a:next:c -> b:val [style=invis]; b:next:c -> c:val; c:next:c -> d:val; { rank=same; cursor:p:s -> null:n; } { rank=same; head:p:s -> a:val; } { rank=same; next:p:s -> b:val; } } ``` `cursor = head` 後 `head=next`出回圈的樣子 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] head [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> node1 </TD> </TR> </TABLE>>]; cursor [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">cursor</TD></TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR><TD PORT="p">NULL</TD></TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node4 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> b:val [style=invis]; b:next:c -> c:val; c:next:c -> d:val; { rank=same; cursor:p:s -> a:val:n; } { rank=same; head:p:s -> b:val; } null:p:e -> a:next:c [dir=back] } ``` ### 第2次進迴圈的情況(57行) ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] head [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; next [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">next</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> node1 </TD> </TR> </TABLE>>]; cursor [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">cursor</TD></TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR><TD PORT="p">NULL</TD></TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node4 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> b:val [style=invis]; b:next:c -> c:val; c:next:c -> d:val; { rank=same; cursor:p:s -> a:val:n; } { rank=same; head:p:s -> b:val; } { rank=same; next:p:s -> c:val; } null:p:e -> a:next:c [dir=back] } ``` 做完 `head->next = cursor` 後 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] head [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> node1 </TD> </TR> </TABLE>>]; next [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">next</TD></TR> </TABLE>>]; cursor [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">cursor</TD></TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR><TD PORT="p">NULL</TD></TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="next"> </TD> <TD PORT="val">node2</TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node4 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:val -> b:next:c [dir=back]; b:next:c -> c:val [style=invis]; c:next:c -> d:val; { rank=same; cursor:p:s -> a:val:n; } { rank=same; head:p:s -> b:val; } { rank=same; next:p:s -> c:val; } null:p:e -> a:next:c [dir=back] } ``` 然後移動指標 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] head [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> node1 </TD> </TR> </TABLE>>]; cursor [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">cursor</TD></TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR><TD PORT="p">NULL</TD></TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="next"> </TD> <TD PORT="val">node2</TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; null2 [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR><TD PORT="p">NULL</TD></TR> </TABLE>>]; a:val -> b:next:c [dir=back]; b:next:c -> c:val [style=invis]; c:next:c -> d:val; d:next:c -> null2:p:w { rank=same; cursor:p:s -> b:val:n; } { rank=same; head:p:s -> c:val; } null:p:e -> a:next:c [dir=back] } ``` 之後依此類推 ### 結束時 結束時 `head` 到達最尾端的 `NULL`,cursor 則指向最後的節點,也就是新的頭,所以回傳 cursor。 ## 延伸問題 2 ### swap_pair 的 pointer to pointer 版本 ```c= void swap_pair(node_t **head){ for(node_t **node = head; *node && (*node)->next; node = &(*node)->next->next){ node_t *tmp = *node; *node = (*node)->next; tmp->next = (*node)->next; (*node)->next = tmp; } } ``` 程式碼原理一致,再開頭時新的運作方式變成: :::warning 括號 head 代表在 main 中的 head。 ::: 1. 第5行 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] nodepp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">node</TD></TR> </TABLE>>]; tmpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">tmp</TD></TR> </TABLE>>]; headp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">(head)</TD></TR> </TABLE>>]; headpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node1 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> b:val; b:next:c -> c:val; c:next:c -> d:val; nodepp:p:s -> headp:p:w; { rank=same; tmpp:p:s -> a:val; } { rank=same; headpp:p:s -> headp:p:n; } headp:p:e -> a:val } ``` 2. 第 6 行 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] nodepp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">node</TD></TR> </TABLE>>]; tmpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">tmp</TD></TR> </TABLE>>]; headp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">(head)</TD></TR> </TABLE>>]; headpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node1 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> b:val; b:next:c -> c:val; c:next:c -> d:val; nodepp:p:s -> headp:p:w; { rank=same; tmpp:p:s -> a:val; } { rank=same; headpp:p:s -> headp:p:n; } headp:p:e -> b:val headp:p:e -> a:val [style=invis] } ``` 3. 第 7 行 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] nodepp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">node</TD></TR> </TABLE>>]; tmpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">tmp</TD></TR> </TABLE>>]; headp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">(head)</TD></TR> </TABLE>>]; headpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node1 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> c:val; b:next:c -> c:val; c:next:c -> d:val; nodepp:p:s -> headp:p:w; { rank=same; tmpp:p:s -> a:val; } { rank=same; headpp:p:s -> headp:p:n; } headp:p:e -> b:val b:p:e -> a:val [style=invis] } ``` 4. 第8行 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] nodepp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">node</TD></TR> </TABLE>>]; tmpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">tmp</TD></TR> </TABLE>>]; headp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">(head)</TD></TR> </TABLE>>]; headpp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> node1 </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node3</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; a:next:c -> c:val; c:next:c -> d:val; nodepp:p:s -> headp:p:w; { rank=same; tmpp:p:s -> a:val; } { rank=same; headpp:p:s -> headp:p:n; } headp:p:e -> b:val b:next:e -> a:val } ``` `head` 在這裡很自然的指向了新的頭,所以完全不需要新增程式碼來處理這部份。 ### reverse 的 pointer to pointer 版本 ```C void reverse(node_t **head) { node_t *cursor = NULL; while (*head) { node_t *next = (*head)->next; (*head)->next = cursor; cursor = *head; *head = next; } *head = cursor; } ``` 這個版本沒做什麼修改,只要將 `head` 都換成 `*head` 即可,回傳的動作則改成直接設定 `*head`。 ## 延伸問題 3 - recursive reverse ```c= node_t *reverse_recursive(node_t *head) { if(!head || !head->next){ return head; } node_t *rev_head = reverse_recursive(head->next); head->next->next = head; head->next = NULL; return rev_head; } void reverse(node_t **head) { *head = reverse_recursive(*head); } ``` ### 程式解說 #### reverse 此函式是為了包裝 reverse 的呼叫成指標的型式,並會完成最後修改頭的動作。 #### reverse_recursive 1. 此函式把 linked list 拆成第一個節點以及後面整串,然後遞迴呼叫翻轉後面整串。 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] headp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node1</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="val">node2</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="val"> ... </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="val"> last node </TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR> <TD PORT="p"> NULL </TD> </TR> </TABLE>>]; a:next:c -> b:val; b:next:c -> c:val; c:next:c -> d:val; d:next:c -> null:p:w; { rank=same; headp:p:s -> a:val; } } ``` 2. 後面翻轉完後回傳的是後面那串新的頭。 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] headp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="val">node1</TD> <TD PORT="next"> </TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="next"> </TD> <TD PORT="val">node2</TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> ... </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> last node </TD> </TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR> <TD PORT="p"> NULL </TD> </TR> </TABLE>>]; rev_head [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="p"> rev_head </TD> </TR> </TABLE>>]; a:next:c -> b:val; a->null [style=invis] b:val -> c:next:c [dir=back]; c:val -> d:next:c [dir=back]; null:p:e -> b:next:c [dir=back] { rank=same; headp:p:s -> a:val; } { rank=same; rev_head:p:s -> d:val} } ``` 3. 再來 ``` head->next->next = head; ``` 目的是要教第一個節點接回到尾巴。 最後再把尾巴的 `next` 設為 `NULL`: ``` head->next = NULL; ``` 做完就變 ```graphviz digraph { rankdir=LR; node [shape=none]; edge [arrowhead=vee,headclip=false, tailclip=false] headp [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR><TD PORT="p">head</TD></TR> </TABLE>>]; a [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="next"> </TD> <TD PORT="val">node1</TD> </TR> </TABLE>>]; b [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="next"> </TD> <TD PORT="val">node2</TD> </TR> </TABLE>>]; c [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> ... </TD> </TR> </TABLE>>]; d [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0" BGCOLOR="lightgrey"> <TR> <TD PORT="next"> </TD> <TD PORT="val"> last node </TD> </TR> </TABLE>>]; null [label=< <TABLE BORDER="0" CELLBORDER="0" cellspacing="0"> <TR> <TD PORT="p"> NULL </TD> </TR> </TABLE>>]; rev_head [label=< <TABLE BORDER="0" CELLBORDER="1" cellspacing="0"> <TR> <TD PORT="p"> rev_head </TD> </TR> </TABLE>>]; null:p:e -> a:next:c [dir=back]; b:val -> c:next:c [dir=back]; c:val -> d:next:c [dir=back]; a:val:e -> b:next:c [dir=back] { rank=same; headp:p:s -> a:val; } { rank=same; rev_head:p:s -> d:val} } ``` 回傳 `rev_head` 就完成了翻轉的動作。 ## 延伸問題 4 - Fisher-Yates Shuffle ```c= void shuffle(node_t **head){ node_t *old_head, *cursor, **indirect; int range = 0; old_head = cursor = *head; // get list length while(cursor){ range += 1; cursor = cursor->next; } // starts Fisher-Yates *head = NULL; for(;range > 0; --range){ indirect = &old_head; // move to selected node for(int i = rand() % range; i > 0; --i){ indirect = &(*indirect)->next; } // move selected node to new list node_t *tmp = *indirect; // holds the node to move *indirect = (*indirect)->next; // skip the node to move tmp->next = *head; // move the node to the head of new list *head = tmp; } } ``` ### 程式解說 + 6~8: 得到 list 長度,後面 Fisher-Yates 要用 + 11: `*head` 作為新的 list 的頭 + 12: Fisher-Yates Shuffle 的迴圈,出迴圈後就完成搬運所有節點了。head也將變成新的 list。 + 15~17: 取得隨機數然後找到第 i 個節點 + 20~23: 將這個節點從舊 list 移到新 list 的頭