# 2020q3 Homework1 (quiz1)
contributed by < `johnnycck` >
###### tags: `sysprog2020`, `quiz`
## :memo: Table of Contents
[TOC]
---
## :page_facing_up: 題目
:::spoiler
考慮一個單向 linked list,其結構定義為:
```c
typedef struct __node {
int value;
struct __node *next;
} node_t;
```
已知不存在 circular (環狀結構),接下來將對該單向 linked list 進行下列操作:
* `add_entry`: 新增節點,當 linked list 沒有內容時,必須由開發者更新指向開頭的指標。因此實際得到 reference,而非 copy
* `remove_entry`: 移除指定節點,指向開頭的指標可能因此變更,所以需要用到 a pointer to a pointer (指標的指標)
* `swap_pair`: 交換一對相鄰的節點,取自 LeetCode: Swap Nodes in Pairs,給定 `1->2->3->4`,則該回傳 `2->1->4->3`
* `reverse`: 將給定的 linked list 其內節點予以反向,即 `1->2->3->4`,則該回傳 `4->3->2->1`
對應的程式碼如下:
```c=
#include <stdio.h>
#include <stdlib.h>
#include <assert.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;
assert(new_node); // AA1
while (*indirect)
indirect = &(*indirect)->next;
*indirect = new_node; // 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; node = &(*node)->next->next) { // BB1
node_t *tmp = *node;
*node = (*node)->next; // 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;
head->next = cursor; // CCC
cursor = head; // 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;
}
```
參考執行輸出: (第 1 行是換行符號)
```c=
72 101 108 109 110 111
72 108 109 110
108 72 110 109
109 110 72 108
```
請補完程式碼。
:::
---
## 程式運作原理
以 `add_entry()`, `find_entry()`, `remove_entry()`, `swap_pair()`, `reverse()`, `print_list()` 等六個 function 組成
----
### add_entry() function 說明
```c=9
void add_entry(node_t **head, int new_value)
{
// 使用雙重指標,indirect 位址跟 head 位址相同
node_t **indirect = head;
// 新增節點 new_node,並依據 Parameter in assign value
node_t *new_node = malloc(sizeof(node_t));
new_node->value = new_value;
new_node->next = NULL;
// 使用 assert Macro 判斷是否 malloc 成功
assert(new_node);
// 要將新建的 node 連上 linked list,*indirect 代表連出去的節點
// 若 *indirect == NULL,代表到了 linked list 的尾端
// 若 *indirect = NULL,則使用 "&" 得到 *indirect 的值,也就是 node
// 再指向 next,得到下一個 node
while (*indirect)
indirect = &(*indirect)->next;
// 將 new_node 接續上 linked list 的尾端
*indirect = new_node;
}
int main()
{
node_t *head = NULL;
add_entry(&head, 72);
add_entry(&head, 101);
add_entry(&head, 108);
add_entry(&head, 109);
// linked list: 72 -> 101 -> 108 -> 109
}
```
* assert() 是一個 Macro,而非一個 function,定義在 ISO C99 中的 <assert.h>
* 型態為:void assert( int expression ),若 expression 為 0,則印出 error message,並執行 abort
### find_entry() function 說明
```c=9
node_t *find_entry(node_t *head, int value)
{
node_t *current = head;
// 從 head 開始,若是 current != NULL 且 current->value 不等於要找的 value 值,往 next 去找
for (; current && current->value != value; current = current->next)
/* interate */;
return current;
}
int main()
{
node_t *entry = find_entry(head, 101);
}
```
### remove_entry() function 說明
```c=9
void remove_entry(node_t **head, node_t *entry)
{
// 將 indirect assign 成 head
node_t **indirect = head;
// 若 *indirect 並不等於 entry,往 next 去找
while ((*indirect) != entry)
indirect = &(*indirect)->next;
// 直接更改 *indirect 成下一筆資料,這樣原先的 node 就自動不在 linked list 當中
*indirect = entry->next;
// 將 entry free 掉,以免發生 memory leak
free(entry);
}
int main()
{
entry = find_entry(head, 111);
remove_entry(&head, entry);
}
```
### swap_pair() function 說明
```c=9
node_t *swap_pair(node_t *head)
{
//
for (node_t **node = &head; *node && (*node)->next; node = &(*node)->next->next) { // BB1
node_t *tmp = *node;
*node = (*node)->next; // BB2
tmp->next = (*node)->next;
(*node)->next = tmp;
}
return head;
}
int main()
{
head = swap_pair(head);
}
```
### reverse() function 說明
```c=9
node_t *reverse(node_t *head)
{
node_t *cursor = NULL;
// 依序從 head 往下做,直到 linked list 的尾端即完成 reverse
while (head) {
// 新增一個 *next 節點,並 assign 成 head->next
node_t *next = head->next;
// 因要 reverse,所以 head->next 會倒過來變 head,所以 head->next assign 成 head
head->next = cursor; // CCC
cursor = head; // CCC
// head assign 成 line 14 的 next
head = next;
}
// 回傳 cursor,現在已變成 reverse 後的 head
return cursor;
}
```
### print_list() function 說明
```c=9
void print_list(node_t *head)
{
// current assign 成 head,只要還沒到結尾,current 就繼續往 next 走
for (node_t *current = head; current; current = current->next)
printf("%d ", current->value);
printf("\n");
}
```