# 2020q3 Homework1 (quiz1) contributed by < `Uduru0522` > ###### tags: `perspective and application of computer systems 2020` [TOC] ---- # 問題 :::info 考慮一 singly linked list , 其結構定義如下: </br> ```c= typedef struct __node{ int value; struct __node *next; }node_t; ``` 已知**不存在環狀結構**,請補完下方程式碼 AA1, AA2, BB1, BB2, CCC 之部分 :::spoiler 點此展開程式碼 **Source Code** ```c= #include <stdio.h> #include <stdlib.h> typedef struct __node { int value; struct __node *next; } node_t; 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; } node_t *find_entry(node_t *head, int value) { node_t *current = head; for (; current && current->value != value; current = current->next) /* interate */; return current; } void remove_entry(node_t **head, node_t *entry) { node_t **indirect = head; while ((*indirect) != entry) indirect = &(*indirect)->next; *indirect = entry->next; free(entry); } 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; } node_t *reverse(node_t *head) { node_t *cursor = NULL; while (head) { node_t *next = head->next; CCC; head = next; } return cursor; } void print_list(node_t *head) { for (node_t *current = head; current; current = current->next) printf("%d ", current->value); printf("\n"); } int main(int argc, char const *argv[]) { node_t *head = NULL; print_list(head); add_entry(&head, 72); add_entry(&head, 101); add_entry(&head, 108); add_entry(&head, 109); add_entry(&head, 110); add_entry(&head, 111); print_list(head); node_t *entry = find_entry(head, 101); remove_entry(&head, entry); entry = find_entry(head, 111); remove_entry(&head, entry); print_list(head); /* swap pair. * See https://leetcode.com/problems/swap-nodes-in-pairs/ */ head = swap_pair(head); print_list(head); head = reverse(head); print_list(head); return 0; } ``` **Output** ```text= 72 101 108 109 110 111 72 108 109 110 108 72 110 109 109 110 72 108 ``` ::: # 各函式分析 ### `add_entry()` ```c= 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 assert(new_node); while (*indirect) indirect = &(*indirect)->next; //AA2 *indirect = new_node; } ``` + 函式首先嘗試取得一塊新的 `node_t` 大小的記憶體空間並初始化: ```graphviz digraph structs{ rankdir = LR node[shape = record] INDIRECT[ style = "filled, rounded" fillcolor = "palegreen" label = " indirect " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL_1[label = "NULL", shape = plain] NULL_2[label = "NULL", shape = plain] new_node[ style = "filled" fillcolor = "lightblue1" label = "{{<f0>new_node|<f1>new_value}|<f2>next}" ] { rank = same; HEAD new_node} INDIRECT -> HEAD HEAD -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> NULL_2 new_node:f2 -> NULL_1 } ``` + `assert()` 於 `<assert.h>` 之下。根據 assert(3): :::warning **If expression is false (i.e., compares equal to zero), `assert()` prints an error message to standard error and terminates the program by calling `abort()`.** The error message includes the name of the file and function containing the `assert()` call, the source code line number of the call, and the text of the argument; something like: prog: file_name.c:16: func_name: Assertion `val == 0' failed. ::: 搭配 `malloc()` , 根據 malloc(3): > on error, these functions return `NULL` 可用來檢測記憶體區塊取得失敗的情形。 + 再向前移動,尋找最後的 NULL pointer ```graphviz digraph structs{ rankdir = LR node[shape = record] INDIRECT[ style = "filled, rounded" fillcolor = "palegreen" label = " indirect " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL_1[label = "NULL", shape = plain] NULL_2[label = "NULL", shape = plain] new_node[ style = "filled" fillcolor = "lightblue1" label = "{{<f0>new_node|<f1>new_value}|<f2>next}" ] { rank = "same" new_node HEAD } INDIRECT -> list_node_1:f2; HEAD -> list_node_1; list_node_1:f2 -> list_node_2; list_node_2:f2 -> NULL_2; new_node:f2 -> NULL_1 } ``` ```graphviz digraph structs{ rankdir = LR node[shape = record] INDIRECT[ style = "filled, rounded" fillcolor = "palegreen" label = " indirect " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL_1[label = "NULL", shape = plain] NULL_2[label = "NULL", shape = plain] new_node[ style = "filled" fillcolor = "lightblue1" label = "{{<f0>new_node|<f1>new_value}|<f2>next}" ] { rank = "same" new_node HEAD } INDIRECT -> list_node_2:f2; HEAD -> list_node_1; list_node_1:f2 -> list_node_2; list_node_2:f2 -> NULL_2; new_node:f2 -> NULL_1 } ``` + 最後再將 `new_node` 接上最後尾 ```graphviz digraph structs{ rankdir = LR node[shape = record] INDIRECT[ style = "filled, rounded" fillcolor = "palegreen" label = " indirect " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL_1[label = "NULL", shape = plain] new_node[ style = "filled" fillcolor = "lightblue1" label = "{{<f0>new_node|<f1>new_value}|<f2>next}" ] { rank = "same" INDIRECT HEAD } INDIRECT -> list_node_2:f2 HEAD -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> new_node new_node:f2 -> NULL_1 } ``` ### `remove_entry()` ```c= void remove_entry(node_t **head, node_t *entry){ node_t **indirect = head; while ((*indirect) != entry) indirect = &(*indirect)->next; *indirect = entry->next; free(entry); } ``` + 此實做需配合前方使用 `find_entry()` 取得欲刪除的節點之前一個節點的 `next` + 假設欲刪除 `node2` (因此 `entry` 等同於 `node.next`) ```graphviz digraph structs{ rankdir = LR node[shape = record] INDIRECT[ style = "filled, rounded" fillcolor = "palegreen" label = " indirect " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] INDIRECT -> HEAD HEAD -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> NULL } ``` + 向前移動 `indirect` ,尋找 `entry` ```graphviz digraph structs{ rankdir = LR node[shape = record] INDIRECT[ style = "filled, rounded" fillcolor = "palegreen" label = " indirect " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] INDIRECT -> list_node_1:f2 HEAD -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> NULL } ``` + 找到之後直接將 `entry->next` 直接接上前方節點 ```graphviz digraph structs{ rankdir = LR node[shape = record] INDIRECT[ style = "filled, rounded" fillcolor = "palegreen" label = " indirect " shape = plain ] BLANK_1[ style = "filled, rounded, invis" label = " " shape = plain ] BLANK_2[ style = "filled, rounded, invis" label = " " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] ENTRY[ style = "filled, rounded" fillcolor = "palegreen" label = " entry " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL[label = " NULL ", shape = plain] { rank = same; INDIRECT BLANK_1 HEAD BLANK_2 ENTRY} INDIRECT -> BLANK_1 -> HEAD -> BLANK_2 -> ENTRY[ style = invis ] INDIRECT -> list_node_1:f2 HEAD -> list_node_1 list_node_1:f2 -> NULL list_node_2:f2 -> NULL ENTRY -> list_node_2 } ``` + 最後將 `entry` 的記憶體釋放掉。 ```graphviz digraph structs{ rankdir = LR node[shape = record] INDIRECT[ style = "filled, rounded" fillcolor = "palegreen" label = " indirect " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{d<f0>node1|<f1>value}|<f2>next}" ] NULL[label = " NULL ", shape = plain] BLANK_1[ label = " " shape = box style = invis ] BLANK_2[ label = " " shape = box style = invis ] { rank = same; HEAD INDIRECT } INDIRECT -> HEAD[style = invis] BLANK_2 -> list_node_1[style = invis] INDIRECT -> HEAD[style = invis] INDIRECT -> list_node_1:f2 HEAD -> list_node_1 list_node_1:f2 -> NULL } ``` ### `swap_pair()` ```c= node_t *swap_pair(node_t *head){ // BB1 for(node_t **node = &head;*node && (*node)->next;node = &(*node)->next->next){ node_t *tmp = *node; // BB2 *node = (*node)->next; tmp->next = (*node)->next; (*node)->next = tmp; } return head; } ``` + 初始狀態: ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" NODE_ HEAD } NODE_ -> HEAD; HEAD -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> list_node_3 list_node_3:f2 -> list_node_4 list_node_4:f2 -> NULL } ``` + 每次進入迴圈,創建一個與 `*node` 相同的暫時指標 ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] TEMP[ style = "filled, rounded" fillcolor = "palegreen" label = " temp " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" NODE_ HEAD TEMP } NODE_ -> HEAD; HEAD -> TEMP[style = invis] HEAD -> list_node_1 TEMP -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> list_node_3 list_node_3:f2 -> list_node_4 list_node_4:f2 -> NULL } ``` + 先將 `*node` 向前移動 ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head \n (Same address as node1.next) " shape = plain ] TEMP[ style = "filled, rounded" fillcolor = "palegreen" label = " temp " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" HEAD TEMP } NODE_ -> HEAD -> list_node_2 TEMP -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> list_node_3 list_node_3:f2 -> list_node_4 list_node_4:f2 -> NULL } ``` + 將 `*node` 目前指向的節點的前項之 `next` 指向後項 ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] TEMP[ style = "filled, rounded" fillcolor = "palegreen" label = " temp " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" HEAD TEMP } NODE_ -> HEAD -> list_node_2 TEMP -> list_node_1 list_node_1:f2 -> list_node_3 list_node_2:f2 -> list_node_3 list_node_3:f2 -> list_node_4 list_node_4:f2 -> NULL } ``` + 再將 `*node` 指向前項,**注意此時 `node_t *head` 也完成了位置的修正** ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] TEMP[ style = "filled, rounded" fillcolor = "palegreen" label = " temp " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" list_node_2 TEMP } NODE_ -> HEAD -> list_node_2 TEMP -> list_node_1 list_node_1:f2 -> list_node_3 list_node_2:f2 -> list_node_1 list_node_3:f2 -> list_node_4 list_node_4:f2 -> NULL } ``` + 將 `node` 前進兩個節點,重複動作。此時 `head` 不會再被移動。 ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" NODE_ list_node_2} HEAD -> list_node_2 NODE_ -> list_node_1:f2 list_node_1:f2 -> list_node_3 list_node_2:f2 -> list_node_1 list_node_3:f2 -> list_node_4 list_node_4:f2 -> NULL } ``` ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] TEMP[ style = "filled, rounded" fillcolor = "palegreen" label = "temp\n (Same as node1.next) " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" NODE_ list_node_2} HEAD -> list_node_2 NODE_ -> list_node_1:f2 TEMP -> list_node_3 list_node_1:f2 -> list_node_3 list_node_2:f2 -> list_node_1 list_node_3:f2 -> list_node_4 list_node_4:f2 -> NULL } ``` ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] TEMP[ style = "filled, rounded" fillcolor = "palegreen" label = "temp\n (Same as node1.next) " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" NODE_ list_node_1} HEAD -> list_node_2 NODE_ -> list_node_3:f2 TEMP -> list_node_3 list_node_1:f2 -> list_node_3 list_node_2:f2 -> list_node_1 list_node_3:f2 -> list_node_4 list_node_4:f2 -> NULL } ``` ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] TEMP[ style = "filled, rounded" fillcolor = "palegreen" label = "temp\n (Same as node1.next) " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" NODE_ list_node_1} HEAD -> list_node_2 NODE_ -> list_node_3:f2 TEMP -> list_node_4 list_node_1:f2 -> list_node_4 list_node_2:f2 -> list_node_1 list_node_3:f2 -> NULL list_node_4:f2 -> NULL } ``` ```graphviz digraph structs{ rankdir = LR node[shape = record] NODE_[ style = "filled, rounded" fillcolor = "palegreen" label = " node " shape = plain ] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] TEMP[ style = "filled, rounded" fillcolor = "palegreen" label = "temp\n (Same as node1.next) " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] list_node_3[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node3|<f1>value}|<f2>next}" ] list_node_4[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node4|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] { rank = "same" TEMP list_node_1 } { rank = "same" NODE_ list_node_4 } HEAD -> list_node_2 NODE_ -> list_node_3:f2 TEMP -> list_node_4 list_node_1:f2 -> list_node_4 list_node_2:f2 -> list_node_1 list_node_3:f2 -> NULL list_node_4:f2 -> list_node_3 } ``` ### `reverse()` ```c= node_t *reverse(node_t *head){ node_t *cursor = NULL; while (head) { node_t *next = head->next; // CCC head->next = cursor; cursor = head; // Until here head = next; } return cursor; } ``` + 以 `cursor` 儲存**已處裡**的部分,`head` 指向**未處理**的部分。 + 初始狀態 ```graphviz digraph structs{ rankdir = LR node[shape = record] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] CURSOR[ style = "filled, rounded" fillcolor = "palegreen" label = " cursor " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] NULL_END[label = "NULL", shape = plain] HEAD -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> NULL CURSOR -> NULL_END } ``` + 新增 `node_t *next`,為下次迴圈中要處理的節點 ```graphviz digraph structs{ rankdir = LR node[shape = record] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] CURSOR[ style = "filled, rounded" fillcolor = "palegreen" label = " cursor " shape = plain ] NEXT[ style = "filled, rounded" fillcolor = "palegreen" label = " next " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] NULL_END[label = "NULL", shape = plain] NEXT -> list_node_2 HEAD -> list_node_1 list_node_1:f2 -> list_node_2 list_node_2:f2 -> NULL CURSOR -> NULL_END } ``` + 將head指向的節點接到 `cursor` 上 ```graphviz digraph structs{ rankdir = LR node[shape = record] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] CURSOR[ style = "filled, rounded" fillcolor = "palegreen" label = " cursor " shape = plain ] NEXT[ style = "filled, rounded" fillcolor = "palegreen" label = " next " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] NULL_END[label = "NULL", shape = plain] NEXT -> list_node_2 HEAD -> list_node_1 list_node_1:f2 -> NULL_END list_node_2:f2 -> NULL CURSOR -> NULL_END } ``` + 將 `cursor` 指向**已處理**部分的開頭 ```graphviz digraph structs{ rankdir = LR node[shape = record] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] CURSOR[ style = "filled, rounded" fillcolor = "palegreen" label = " cursor " shape = plain ] NEXT[ style = "filled, rounded" fillcolor = "palegreen" label = " next " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] NULL_END[label = "NULL", shape = plain] BLANK[shape = plain, label = " ", style = invis] { rank = same; CURSOR HEAD BLANK NEXT } CURSOR -> HEAD -> BLANK -> NEXT[style = invis] NEXT -> list_node_2 HEAD -> list_node_1 list_node_1:f2 -> NULL_END list_node_2:f2 -> NULL CURSOR -> list_node_1 } ``` + 再將 `head` 指回**未處理**部分的開頭,重複迴圈直到 `head` 指向 `NULL` ```graphviz digraph structs{ rankdir = LR node[shape = record] HEAD[ style = "filled, rounded" fillcolor = "palegreen" label = " head " shape = plain ] CURSOR[ style = "filled, rounded" fillcolor = "palegreen" label = " cursor " shape = plain ] NEXT[ style = "filled, rounded" fillcolor = "palegreen" label = " next " shape = plain ] list_node_1[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node1|<f1>value}|<f2>next}" ] list_node_2[ style = "filled" fillcolor = "lightskyblue3" label = "{{<f0>node2|<f1>value}|<f2>next}" ] NULL[label = "NULL", shape = plain] NULL_END[label = "NULL", shape = plain] BLANK[shape = plain, label = " ", style = invis] { rank = same; CURSOR HEAD BLANK NEXT } CURSOR -> BLANK -> HEAD -> NEXT[style = invis] NEXT -> list_node_2 HEAD -> list_node_2 list_node_1:f2 -> NULL_END list_node_2:f2 -> NULL CURSOR -> list_node_1 } ``` ### `find_entry()` ```c= node_t *find_entry(node_t *head, int value){ node_t *current = head; for (; current && current->value != value; current = current->next); return current; } ``` + 使用 `for` 終止條件進行搜尋。 + 判斷式 `current && current->value != value` 利用 `&&` 的 **short-circut evaluation** 特性,在 `current == NULL` 時不進行後方的取值動作。 :::warning `&&` `||` `?` 三個 operator 有這項特性,若第一個 expression 已可以確定結果(例如 `false && X` 必為 `false`),右方 expression 便不會被執行 ::: + 回傳值若非 `NULL` ,必為上一個節點的 `next` 值,方便搭配 `remove_entry()` 使用 ### `print_list()` ```c= void print_list(node_t *head){ for (node_t *current = head; current; current = current->next) printf("%d ", current->value); printf("\n"); } ``` 自 `head` 開始在 list 之中進行穿隧並逐一印出 `value` ,很直覺。 ---- # 延伸問題 ### Q1-1. 以 pointer-to-pointer 實做 `swap_pair()`。 由於原先的實做中的 `node_t **node` 單純只是複製一份 pointer-to-pointer , 我們可以在修正傳入參數之後,直接代換以達成效果。 ```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; } } ``` ### Q1-2 以 pointer-to-pointer 實做 `reverse()`。 同 Q1-1。 由於 `cursor` 會指向已倒序完成的 list , 最後將它接回 `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; } ``` ### Q2. 以遞迴方式實作 `reverse()`。 沿用原本的實作邏輯,但將 while 迴圈改成以遞迴的方式實現。 `done` 指向已處理的部分,`remain` 指向未處理的部分,每層迴圈將 `remain` 的第一個加進相反 `done` 裡。 ```c= node_t *reverse_recursive(node_t *remain, node_t *done){ if (!remain){ return done; } node_t *next = remain->next; remain->next = done; return reverse_recursive(next, remain); } void reverse(node_t **head){ *head = reverse_recursive(*head, NULL); } ``` ### Q3. 針對 singly-linked list 中的節點,實作 Fisher-Yates shuffle。 流程如下: 1. 以一 `prev_head` 暫時節點,後方街上整個 list。 2. 先尋找到需要往後移的節點( `target` ) ,將其前方及後方接上 3. 再將 `destination` 移到目標地 4. 將 `target` 移到該處 5. 最後將適當的 head 回傳 ```c= void shuffle(node_t **head){ // Find length of LL size_t length = 0; for(node_t *temp = *head; temp; temp = temp->next){ ++length; } printf("Length of LL is %u.\n", length); // Fisher-Yates shuffle node_t *target = NULL, *prev = NULL, *destination = NULL; node_t *prev_head = malloc(sizeof(struct __node)); prev_head->next = *head; int target_pos; srand(time(NULL)); for(int i = length; i; --i){ target_pos = rand() % i; printf("Shuffler picked index %d.\n", target_pos); // Get moving target target = prev_head->next; prev = prev_head; // printf("p @ [%p], t @ [%p], d @ [%p]\n", prev, target, destination); for(int j = target_pos; j; --j){ prev = target; target = target->next; } // No need to swap if(!(i - target_pos - 1)){ continue; } // Connect gap after getting the target prev->next = target->next; // Move to slot at position i - rand_result destination = target; for(int j = i - target_pos - 1; j; --j){ destination = destination->next; } // Put target into designed destination target->next = destination->next; destination->next = target; print_list(prev_head->next); printf("\n"); } *head = prev_head->next; } ``` > TODO: 本實作需要在迴圈中判斷是否有移動必要;再嘗試將其解決