# 2020q3 Homework1 (quiz1) contributed by < `ccs100203` > ###### tags: `linux2020` ## 程式運作原理 ### swap_pair ```c= node_t *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; } return head; } ``` 1. 一開始會有一個 `node` 為 pointer to pointer,然後 for 會判斷說這一個跟下一個是不是 NULL,不是的話就可以做 swap,每一次做完就讓 node 往後指兩個。 2. 先用一個 tmp 指向 *node 指的地方 ```graphviz digraph linked_list{ rankdir = LR; node [shape = record]; subgraph cluster_0 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; label = "pointer to pointer"; node_; }; subgraph cluster_1 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; label = "list"; a; b; c; d; }; node_ -> a; a -> b -> c -> d; tmp -> a } ``` 3. 將 *node 指向 *node->next ```graphviz digraph linked_list{ rankdir = LR; node [shape = record]; subgraph cluster_0 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; label = "pointer to pointer"; node_; }; subgraph cluster_1 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; label = "list"; a; b; c; d; }; node_ -> b; a -> b -> c -> d; tmp -> a } ``` 4. 將 tmp->next 接上 (*node)->next ```graphviz digraph linked_list{ rankdir = LR; node [shape = record]; subgraph cluster_0 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; label = "pointer to pointer"; node_; }; subgraph cluster_1 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; a; b; c; d; }; node_ -> b; b -> c -> d; a -> c; tmp -> a; } ``` 5. 最後再把 (*node)->next 往前接回 tmp ```graphviz digraph linked_list{ rankdir = LR; node [shape = record]; subgraph cluster_0 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; label = "pointer to pointer"; node_; }; subgraph cluster_1 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; a; b; c; d; }; node_ -> b; c -> d; a -> c; b -> a; tmp -> a; } ``` 6. 讓 `node` 往後指到下兩個,node = &(*node)->next->next ```graphviz digraph linked_list{ rankdir = LR; node [shape = record]; subgraph cluster_0 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; label = "pointer to pointer"; node_; }; subgraph cluster_1 { style = "filled"; color = "black"; fillcolor = "lightyellow"; node [style = filled, fillcolor = white, color = black]; a; b; c; d; }; node_ -> c; c -> d; a -> c; b -> a; tmp -> a; } ``` ## 更改為 pointer to pointer ### swap_pair 將 `head` 直接取代掉原本的 `node`,因為 `node` 做的事情就是一直去找後兩個 pointer,所以當我傳 pointer to pointer 的 `head` 時,就可以用他來達成這項功能 ```c= void swap_pair(node_t **head) { for (; *head && (*head)->next; head = &(*head)->next->next) { node_t *tmp = *head; *head = (*head)->next; tmp->next = (*head)->next; (*head)->next = tmp; } } ``` ### reverse 將最後的 `head` 重新指向 `cursor` 指的地方就好了,因為照著原本的邏輯跑,`cursor` 在最後會指向一開始的尾巴,也就是 reverse 過後新的起點,而 `head` 則會跑去指向 `NULL`,這時候只要把 `head` 拉過去指向新的起點就可以了 ```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; } ``` ## 更改 reverse 為 recursive version 目前是做出最直觀的寫法,就是直接把原本 iterate 的版本套下去改成遞迴,還在思索有沒有更好的寫法,因為一直 call function 成本不低 ```c= void rev_recursive(node_t **head, node_t *cursor){ if(*head){ node_t *next = (*head)->next; (*head)->next = cursor; cursor = *head; *head = next; rev_recursive(head, cursor); }else{ *head = cursor; } } void reverse(node_t **head) { rev_recursive(head, NULL); } ``` ## Fisher–Yates shuffle ### Modern method 先計算出 `size`,直觀的從大到小跑迴圈,在每一次的範圍內做 random,並且將得到的數字按照順序跟 size~1 的值做交換 因為交換的順序是從最後面到前面,不斷的交換數值,比起 array 用 singly-linked list 不是很有效率,但目前還沒想到解法 ```c= void shuffle(node_t *head) { srand(time(NULL)); int size = 0; for(node_t *tmp = head; tmp!=NULL; tmp=tmp->next) size++; for(int i=size; i>1; i--){ int num = rand() % i; node_t *tmpA = head, *tmpB = head; for(int j=0; j<num; ++j) tmpA = tmpA->next; for(int j=0; j<i-1; ++j) tmpB = tmpB->next; int val = tmpA->value; tmpA->value = tmpB->value; tmpB->value = val; } } ```