# 2020q3 Homework1 (quiz1)
contributed by < `Rsysz` >
###### tags: `sysprog`
## Outline
[TOC]
## 1. 解釋程式運作原理
由`add_entry`, `find_entry`, `remove_entry`, `swap_pair`, `reverse`, `print_list`構成
* **`add_entry`**
```cpp=
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;
}
```
透過`node_t **indirect`存取`head`內保存的記憶體位址,接著建立新節點`new_node`分配記憶體空間與賦值,另外由此可知`node_t **head`是多餘的,程式碼可修改為`void add_entry(node_t **indirect, int new_value)`
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
indirect [label = "{addr|indirect|<ref>}"];
entry_head [label="{addr|head|<ref>}"];
head [label = "{addr|(main)head|<ref>}"];
new_node [label = "{addr|new_node|<ref>}"];
memory [label = "{addr|value|<ref>next}"];
memory_head [label = "{addr|value|<ref>next}"];
indirect:ref -> head;
entry_head:ref -> head;
head:ref -> memory_head;
new_node:ref -> memory;
memory:ref -> NULL;
}
```
利用`assert(new_node)`確保正確分配記憶體,透過`*indirect`遍歷Link list找到末端節點
並接上新節點
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
indirect [label = "{addr|indirect|<ref>}"];
head [label = "{addr|*indirect|<ref>}"];
new_node [label = "{addr|new_node|<ref>}"];
memory [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_1|<ref>next}"];
memory_tail [label = "{addr|value_2|<ref>next}"];
memory_mid:ref -> memory_tail;
memory_tail:ref -> memory;
indirect:ref -> head;
head:ref -> memory_tail:ref;
new_node:ref -> memory;
memory:ref -> NULL;
}
```
* **`find_entry`**
```cpp=
node_t *find_entry(node_t *head, int value)
{
node_t *current = head;
for (; current && current->value != value; current = current->next);
/* interate */
return current;
}
```
透過`head`遍歷Link list尋找value對應的節點
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
head [label="{addr|head|<ref>}"];
memory_head [label = "{addr|value_1|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
head:ref -> memory_mid;
memory_head:ref -> memory_mid;
memory_mid:ref -> memory_tail;
}
```
* **`remove_entry`**
```cpp=
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`找到對應的節點後將其放入`entry`,再使用`remove_entry`刪除指定的節點
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
indirect [label = "{addr|indirect|<ref>}"];
entry_head [label="{addr|head|<ref>}"];
head [label = "{addr|(main)head|<ref>}"];
entry [label = "{addr|entry|<ref>}"];
memory [label = "{addr|value|<ref>next}"];
memory_head [label = "{addr|value|<ref>next}"];
indirect:ref -> head;
entry_head:ref -> head;
head:ref -> memory_head;
entry:ref -> memory;
memory:ref -> NULL;
}
```
而`remove_entry`使用`*indrect`遍歷Link list找尋指定的節點並予以刪除
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
indirect [label = "{addr|indirect|<ref>}"];
head [label = "{addr|*indirect|<ref>}"];
entry [label = "{addr|entry|<ref>}"];
memory [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_1|<ref>next}"];
memory_tail [label = "{addr|value_2|<ref>next}"];
memory_mid:ref -> memory_tail;
memory_tail:ref -> memory;
indirect:ref -> head;
head:ref -> memory_mid:ref;
entry:ref -> memory_tail;
memory:ref -> NULL;
}
```
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
indirect [label = "{addr|indirect|<ref>}"];
head [label = "{addr|*indirect|<ref>}"];
memory [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_1|<ref>next}"];
memory_mid:ref -> memory;
indirect:ref -> head;
head:ref -> memory_mid:ref;
memory:ref -> NULL;
}
```
* **`swap_pair`**
```cpp=
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`遍歷Link list 每兩個節點交換一次
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
tmp_node [label = "{addr|*node|<ref>}"];
tmp [label = "{addr|tmp|<ref>}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_head [label = "{addr|value_1|<ref>next}"];
memory_head:ref -> memory_mid;
memory_mid:ref -> memory_tail;
tmp:ref -> memory_head;
tmp_node:ref -> memory_mid;
}
```
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
tmp_node [label = "{addr|*node|<ref>}"];
tmp [label = "{addr|tmp|<ref>}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_head [label = "{addr|value_1|<ref>next}"];
memory_head:ref -> memory_tail;
memory_mid:ref -> memory_head;
tmp:ref -> memory_head;
tmp_node:ref -> memory_mid;
}
```
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
top_node [label = "{addr|node|<ref>}"];
tmp_node [label = "{addr|*node|<ref>}"];
tmp [label = "{addr|tmp|<ref>}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_head [label = "{addr|value_1|<ref>next}"];
memory_head:ref -> memory_tail;
memory_mid:ref -> memory_head;
tmp:ref -> memory_head;
top_node:ref -> tmp_node;
tmp_node:ref -> memory_tail;
}
```
* **`reverse`**
```cpp=
node_t *reverse(node_t *head)
{
node_t *cursor = NULL;
while (head) {
node_t *next = head->next;
head->next = cursor; //CCC
cursor = head;
head = next;
}
return cursor;
}
```
透過`next`保留後續Link list
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
cursor [label = "{addr|cursor|<ref>}"];
next [label = "{addr|next|<ref>}"];
head [label = "{addr|head|<ref>}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_head [label = "{addr|value_1|<ref>next}"];
next:ref -> memory_mid;
head:ref -> memory_head;
memory_head:ref -> memory_mid;
memory_mid:ref -> memory_tail;
cursor:ref -> NULL;
}
```
透過`cursor`反轉Link list
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
cursor [label = "{addr|cursor|<ref>}"];
next [label = "{addr|next|<ref>}"];
head [label = "{addr|head|<ref>}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_head [label = "{addr|value_1|<ref>next}"];
next:ref -> memory_mid;
head:ref -> memory_mid;
memory_head:ref -> NULL;
memory_mid:ref -> memory_tail;
cursor:ref -> memory_head;
}
```
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
cursor [label = "{addr|cursor|<ref>}"];
next [label = "{addr|next|<ref>}"];
head [label = "{addr|head|<ref>}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_head [label = "{addr|value_1|<ref>next}"];
next:ref -> memory_tail;
head:ref -> memory_mid;
memory_head:ref -> NULL;
memory_mid:ref -> memory_head;
cursor:ref -> memory_head;
}
```
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
cursor [label = "{addr|cursor|<ref>}"];
next [label = "{addr|next|<ref>}"];
head [label = "{addr|head|<ref>}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_head [label = "{addr|value_1|<ref>next}"];
next:ref -> memory_tail;
head:ref -> memory_tail;
memory_head:ref -> NULL;
memory_mid:ref -> memory_head;
cursor:ref -> memory_mid;
}
```
* **`print_list`**
```cpp=
void print_list(node_t *head)
{
for (node_t *current = head; current; current = current->next)
printf("%d ", current->value);
printf("\n");
}
```
透過`head`遍歷Link list印出所有`value`
```graphviz
digraph add_entry{
node [shape=record];
rankdir=LR;
head [label = "{addr|head|<ref>}"];
memory_tail [label = "{addr|value_3|<ref>next}"];
memory_mid [label = "{addr|value_2|<ref>next}"];
memory_head [label = "{addr|value_1|<ref>next}"];
head:ref -> memory_mid;
memory_head:ref -> memory_mid;
memory_mid:ref -> memory_tail;
memory_tail:ref -> NULL;
}
```
## 2. 修改函式 swap_pair 和 reverse,以pointer to pointer避免回傳
```cpp=
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;
}
}
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;
}
```
## 3. 改寫 reverse,新增rev_recursive遞迴反轉Link list
```cpp=
node_t *rev_recursive(node_t *cursor, node_t *head)
{
if(!head)
return cursor;
node_t *next = head->next;
head->next = cursor;
return rev_recursive(head, next);
}
void reverse(node_t **head)
{
if(!(*head))
return;
*head = rev_recursive(NULL, *head);
}
```
## 4. 實作 Fisher–Yates shuffle,使用swap減少記憶體使用量
```cpp=
void shuffle(node_t **head)
{
srand(time(NULL));
int size = 0;
node_t *tmp = *head;
while(tmp){
size++;
tmp = tmp->next;
}
while(size != 0)
{
node_t *tail, *prev_tmp = NULL, *prev_tail = NULL;
int rad = rand() % size;
tmp = tail = *head;
for(int i = 0; i < rad; i++){
prev_tmp = tmp;
tmp = tmp->next;
}
for(int j = 0; j < size - 1; j++){
prev_tail = tail;
tail = tail->next;
}
/*prev_swap & head*/
if(prev_tmp != NULL)
prev_tmp->next = tail;
else
*head = tail;
if(prev_tail != NULL)
prev_tail->next = tmp;
else
*head = tmp;
/*swap*/
node_t *next = tmp->next;
tmp->next = tail->next;
tail->next = next;
size--;
}
}
```