# 2020q3 Homework1 (quiz1)
contributed by < `nelsonlai1` >
## 1
:::info
1.解釋上述程式運作原理,搭配 Graphviz,比照 Linked List 練習題 在 HackMD 筆記上視覺化展現
:::
### **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;
assert(new_node);
while (*indirect)
indirect = &(*indirect)->next;
*indirect = new_node;
}
```
一開始在初始化`new_node`,分配記憶體空間,assign值以及next。
`assert(new_node)`用來確保malloc成功。
```graphviz
digraph linkedlist {
rankdir=LR;
node[shape=box];
struct5 [label="new_node"]
struct0 [label= "indirect(head)", color=blue];
struct1 [label= "1(*indirect)"];
struct2 [label= "NULL"];
struct3 [label= "NULL"];
struct4 [label= "2"];
{
rank="same";
struct0 -> struct1 [color=blue]
}
struct1 -> struct4
struct4 -> struct2
struct5 -> struct3
}
```
當`*indirect`存在時不斷向後指直到遇到NULL
```graphviz
digraph linkedlist {
rankdir=LR;
node[shape=box];
struct5 [label="new_node"]
struct0 [label= "indirect", color=blue];
struct6 [label= "head", color=blue];
struct1 [label= "1"];
struct2 [label= "NULL"];
struct3 [label= "NULL"];
struct4 [label= "2(*indirect)"];
{
rank="same";
struct0 -> struct4 [color=blue]
}
{
rank="same";
struct6 -> struct1 [color=blue]
}
struct1 -> struct4
struct4 -> struct2
struct5 -> struct3
}
```
```graphviz
digraph linkedlist {
rankdir=LR;
node[shape=box];
struct5 [label="new_node"]
struct0 [label= "indirect", color=blue];
struct6 [label= "head", color=blue];
struct1 [label= "1"];
struct2 [label= "*indirect(NULL)"];
struct3 [label= "NULL"];
struct4 [label= "2"];
{
rank="same";
struct0 -> struct2 [color=blue]
}
{
rank="same";
struct6 -> struct1 [color=blue]
}
struct1 -> struct4
struct4 -> struct2
struct5 -> struct3
}
```
將該node改為new_node
```graphviz
digraph linkedlist {
rankdir=LR;
node[shape=box];
struct5 [label="new_node"]
struct0 [label= "indirect", color=blue];
struct6 [label= "head", color=blue];
struct1 [label= "1"];
struct3 [label= "NULL"];
struct4 [label= "2"];
{
rank="same";
struct0 -> struct5 [color=blue]
}
{
rank="same";
struct6 -> struct1 [color=blue]
}
struct1 -> struct4
struct4 -> struct5
struct5 -> struct3
}
```
### **find_entry** :
```c=
node_t *find_entry(node_t *head, int value)
{
node_t *current = head;
for (; current && current->value != value; current = current->next)
/* interate */;
return current;
}
```
從頭開始檢查`value`是不是要搜尋的,如果不是就繼續往下找,直到找到或是指到NULL為止。
### **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);
}
```
`*indirect`不為`entry`時,`indirect`一直往後移
```graphviz
digraph linkedlist {
rankdir=LR;
node[shape=box];
struct0 [label= "indirect(head)", color = blue];
struct1 [label= ""];
struct2 [label= ""];
struct3 [label= "entry"];
struct4 [label= "e_next"];
{
rank="same";
struct0 -> struct1 [color=blue]
}
struct1 -> struct2
struct2 -> struct3
struct3 -> struct4
}
```
```graphviz
digraph linkedlist {
rankdir=LR;
node[shape=box];
struct0 [label= "indirect", color = blue];
struct5 [label= "head", color = blue];
struct1 [label= ""];
struct2 [label= ""];
struct3 [label= "entry"];
struct4 [label= "e_next"];
{
rank="same";
struct0 -> struct2 [color=blue]
}
{
rank="same";
struct5 -> struct1 [color=blue]
}
struct1 -> struct2
struct2 -> struct3
struct3 -> struct4
}
```
```graphviz
digraph linkedlist {
rankdir=LR;
node[shape=box];
struct0 [label= "indirect", color = blue];
struct5 [label= "head", color = blue];
struct1 [label= ""];
struct2 [label= ""];
struct3 [label= "entry"];
struct4 [label= "e_next"];
{
rank="same";
struct0 -> struct3 [color=blue]
}
{
rank="same";
struct5 -> struct1 [color=blue]
}
struct1 -> struct2
struct2 -> struct3
struct3 -> struct4
}
```
當`*indirect`為`entry`,將`*indirect`改為`entry->next`(圖中用e_next代稱),最後將`entry`釋放掉
```graphviz
digraph linkedlist {
rankdir=LR;
node[shape=box];
struct0 [label= "indirect", color = blue];
struct5 [label= "head", color = blue];
struct1 [label= ""];
struct2 [label= ""];
struct3 [label= "entry"];
struct4 [label= "e_next"];
{
rank="same";
struct0 -> struct4 [color=blue]
}
{
rank="same";
struct5 -> struct1 [color=blue]
}
struct1 -> struct2
struct2 -> struct4
}
```
### **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;
}
```
for迴圈的判斷為先檢查前兩項node是否存在,如果有的話做完迴圈內的指令後,將移往第三、四項,以此類推直到最後一項或NULL為止。
```graphviz
digraph linkedlist {
rankdir = LR
node[shape = box]
struct0 [label = "node", color = blue]
struct1 [label = "1(head)(*node)(tmp)"]
struct2 [label = "2"]
struct3 [label = "3"]
struct4 [label = "4"]
{
rank="same";
struct0 -> struct1[color=blue]
}
struct1 -> struct2 -> struct3 ->struct4
}
```
*node = (*node)->next;
```graphviz
digraph linkedlist {
rankdir = LR
node[shape = box]
struct0 [label = "node", color = blue]
struct1 [label = "1(tmp)"]
struct2 [label = "2(head)(*node)"]
struct3 [label = "3"]
struct4 [label = "4"]
{
rank="same";
struct0 -> struct2[color=blue]
}
struct1 -> struct2 -> struct3 ->struct4
}
```
tmp->next = (*node)->next;
```graphviz
digraph linkedlist {
rankdir = LR
node[shape = box]
struct0 [label = "node", color = blue]
struct1 [label = "1(tmp)"]
struct2 [label = "2(head)(*node)"]
struct3 [label = "3"]
struct4 [label = "4"]
{
rank="same";
struct0 -> struct2[color=blue]
}
struct1 -> struct3
struct2 -> struct3 ->struct4
}
```
(*node)->next = tmp;
```graphviz
digraph linkedlist {
rankdir = LR
node[shape = box]
struct0 [label = "node", color = blue]
struct1 [label = "1(tmp)"]
struct2 [label = "2(head)(*node)"]
struct3 [label = "3"]
struct4 [label = "4"]
{
rank="same";
struct0 -> struct2[color=blue]
}
struct2 -> struct1
struct1 -> struct3 ->struct4
}
```
node = &(*node)->next->next
```graphviz
digraph linkedlist {
rankdir = LR
node[shape = box]
struct0 [label = "node", color = blue]
struct1 [label = "1(tmp)"]
struct2 [label = "2(head)"]
struct3 [label = "3(*node)"]
struct4 [label = "4"]
{
rank="same";
struct0 -> struct3[color=blue]
}
struct2 -> struct1
struct1 -> struct3 ->struct4
}
```
### **reverse** :
```c=
node_t *reverse(node_t *head)
{
node_t *cursor = NULL;
while (head) {
node_t *next = head->next;
head->next = cursor;
cursor = head;
head = next;
}
return cursor;
}
```
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "cursor(NULL)"]
struct1 [label = "1(head)"]
struct2 [label = "2"]
struct3 [label = "3"]
struct1 -> struct2 -> struct3 -> NULL
}
```
node_t *next = head->next;
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "cursor(NULL)"]
struct1 [label = "1(head)"]
struct2 [label = "2(next)"]
struct3 [label = "3"]
struct1 -> struct2 -> struct3 -> NULL
}
```
head->next = cursor;
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "cursor(NULL)"]
struct1 [label = "1(head)"]
struct2 [label = "2(next)"]
struct3 [label = "3"]
struct1 -> struct0
struct2 -> struct3 -> NULL
}
```
cursor = head;
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1(head)(cursor)"]
struct2 [label = "2(next)"]
struct3 [label = "3"]
struct1 -> struct0
struct2 -> struct3 -> NULL
}
```
head = next;
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1(cursor)"]
struct2 [label = "2(next)(head)"]
struct3 [label = "3"]
struct1 -> struct0
struct2 -> struct3 -> NULL
}
```
next loop
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1(cursor)"]
struct2 [label = "2(head)"]
struct3 [label = "3(next)"]
struct1 -> struct0
struct2 -> struct3 -> NULL
}
```
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1(cursor)"]
struct2 [label = "2(head)"]
struct3 [label = "3(next)"]
struct1 -> struct0
struct2 -> struct1
struct3 -> NULL
}
```
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1"]
struct2 [label = "2(head)(cursor)"]
struct3 [label = "3(next)"]
struct1 -> struct0
struct2 -> struct1
struct3 -> NULL
}
```
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1"]
struct2 [label = "2(cursor)"]
struct3 [label = "3(next)(head)"]
struct1 -> struct0
struct2 -> struct1
struct3 -> NULL
}
```
next loop
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1"]
struct2 [label = "2(cursor)"]
struct3 [label = "3(head)"]
struct4 [label = "NULL(next)"]
struct1 -> struct0
struct2 -> struct1
struct3 -> struct4
}
```
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1"]
struct2 [label = "2(cursor)"]
struct3 [label = "3(head)"]
struct4 [label = "NULL(next)"]
struct1 -> struct0
struct2 -> struct1
struct3 -> struct2
}
```
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1"]
struct2 [label = "2"]
struct3 [label = "3(head)(cursor)"]
struct4 [label = "NULL(next)"]
struct1 -> struct0
struct2 -> struct1
struct3 -> struct2
}
```
```graphviz
digraph linkedlist {
rankdir = LR
node [shape = box]
struct0 [label = "NULL"]
struct1 [label = "1"]
struct2 [label = "2"]
struct3 [label = "3(cursor)"]
struct4 [label = "NULL(next)(head)"]
struct1 -> struct0
struct2 -> struct1
struct3 -> struct2
}
```
最後再return cursor作為head
## 2
:::info
2.函式 swap_pair 和 reverse 對於指標的操作方式顯然異於 add_entry 及 remove_entry,需要額外做 head = ... 的更新,請用指標的指標來改寫,並避免回傳指標
:::
```c=
void swap_mod(node_t **head)
{
for (; *head && (*head)->next; head = &(*head)->next->next) {
node_t *indirect = *head;
*head = (*head)->next;
indirect->next = (*head)->next;
(*head)->next = indirect;
}
}
```
```c=
void reverse_mod(node_t **head)
{
node_t *cursor = NULL;
while (*head) {
node_t *next = (*head)->next;
(*head)->next = cursor;
cursor = *head;
*head = next;
}
*head = cursor;
}
```
這部分有點像照樣造句,第一個將node改成head,第二個將head改成*head
## 3
:::info
3.以遞迴改寫上述的 reverse,注意,你可能因此需要建立新的函式,如 rev_recursive,隨後在 reverse 函式中呼叫 rev_recursive
:::
```c=
node_t *rev_recursive(node_t *head, node_t *cursor)
{
if(!head)
return cursor;
node_t *next = head->next;
head->next = cursor;
cursor = head;
head = next;
return rev_recursive(head, cursor);
}
```
在main中呼叫 `head = rev_recursive(head, NULL);`
這裡其實就是將原本的loop改成recursive,而因為`head`, `cursor`兩個node都需要隨時更新,所以需要引用這兩個變數。
## 4
:::info
4.針對 singly-linked list 的節點,實作 [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle),你應該儘量降低記憶體的使用量
:::
這裡實作的方法為wiki中提到的modern method,也就是先從範圍(=list size)中選一個數,與範圍中最後一個交換。接著將範圍減一,重複動作直到完成。
```c=
void shuffle(node_t **head)
{
srand(time(NULL));
int size = 0;
node_t *count = *head;
while (count) {
size++;
count = count->next;
}
while (size > 1) {
node_t *swap, *swap_prev, *tail, *tail_prev;
int ran = rand() % size + 1;
printf("%d\n", ran);
if (ran == size) {
size--;
continue;
}
swap = tail = *head;
for (int i = 0; i < size - 1; i++) {
tail_prev = tail;
tail = tail->next;
}
for (int j = 0; j < ran - 1; j++) {
swap_prev = swap;
swap = swap->next;
}
if (ran == size - 1) {
swap->next = tail->next;
tail->next = swap;
} else {
node_t *tmp_next = swap->next;
swap->next = tail->next;
tail->next = tmp_next;
tail_prev->next = swap;
}
if (ran > 1)
swap_prev->next = tail;
else
*head = tail;
size--;
}
}
```
一開始先利用`count`來算出list的大小當作範圍。
當範圍等於0或1不必交換所以while回圈內的判斷為`size > 1`,而另四個node分別是`swap`, `swap_prev`, `tail`, `tail_prev`分別為要交換的node, 最後一項node以及它們的前一項node。
當隨機選到的數與範圍一樣大時也不用交換,所以將範圍減一後continue。
當選到的數與最後一項node相鄰時,在執行`tail->next` = `tmp_next`(此時為`tail`),以及`tail_prev(此時為swap)->next` = `swap`時會出錯,所以這裡額外判斷操作。
最後判斷選到的數是否為第一個數,來決定更新`*head`或是`swap_prev->next`。