# 2020q3 Homework (quiz1)
contributed by < `nickchenchj` >
###### tags: `sysprog2020`
## Prerequisite
* [problems for quiz1 (2020q3)](https://hackmd.io/@sysprog/sysprog2020-quiz1)
## Explanation
###### Note: all codes below are written in C language, and they can be found in my [GitHub repository](https://github.com/nickchenchj/Computer-Systems)
### Structure of Singly Linked List (SLL)
To define the structure of singly linked list (SLL), **`struct`** statement is required. The structure of SLL is represented as:
```c
typedef struct __node {
int value;
struct __node *next;
} node_t;
```
* schematic representation of SLL:
```graphviz
digraph SLL {
rankdir=LR
node [shape=record]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> value1 | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> value2 | <next> }"
]
NULL [shape=plaintext]
head -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> NULL [tailclip=false]
}
```
###### Note: no circular SLL exist
### Basic Operations on SLL
* **`add_entry`**: appends a new node to the list
* **`find_entry`**: finds a specific node and returns its address
* **`remove_entry`**: removes a specific node and frees its memory by using `pointer to pointer`
* **`swap_pair`**: swaps nodes in pairs (e.g. {1, 2, 3, 4} => {2, 1, 4, 3}; For more information, see [LeetCode: Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/))
* **`reverse`**: reverses the given list by using `rev_recursive` (e.g. {1, 2, 3, 4} => {4, 3, 2, 1})
* **`rev_recursive`:** reverses the given list recursively
* **`print_list`**: prints all the nodes in the list
### Solutions to AA1 and AA2
* code snippet of `add_entry`:
```c=
/* Appends a new node to the list */
void add_entry(node_t **head, int new_value)
{
/* Creates a pointer to pointer called `indirect`
* and makes it point to the address of `head`
* in the list */
node_t **indirect = head;
node_t *new_node = malloc(sizeof(node_t));
AA1;
new_node->value = new_value;
new_node->next = NULL;
/* (*indirect) is the value (address of a node)
* of the pointer that indirect points to */
while (*indirect)
/* indirect points to the pointer
* which points to the next node */
indirect = &(*indirect)->next;
AA2;
}
```
#### AA1 = ?
* `(a)` `assert(new_node)`
* `(b)` `*indirect = new_node`
:::info
**Idea**
Remember, always make sure that memory allocation is successful before changing the values of the new node (`NULL` will be returned if memory allocation fails). To prevent dereferencing null pointers, `assert(new_node)` will be an ideal choice of this problem.
:::
:::success
Answer: `(a)` `assert(new_node)`
:::
#### AA2 = ?
* `(a)` `assert(new_node)`
* `(b)` `*indirect = new_node`
:::info
**Idea**
1. Find the last node.
2. Append a new node to the end of the list.
:::
#### Implementation
1. Store the address of `head` into `indirect`:
```graphviz
digraph add_entry{
rankdir=LR
node [shape=record]
indirect [
label="indirect"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
indirect -> head:address [color=red]
head -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> NULL [tailclip=false]
}
```
2. Let `indirect` store the address of `*indirect->next` until `*indirect` == `NULL`:
* **After the 1st iteration:**
```graphviz
digraph add_entry{
rankdir=LR
node [shape=record]
indirect [
label="indirect"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
indirect -> node1:next [color=red]
head -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> NULL [tailclip=false]
}
```
* **After the 2nd iteration:**
```graphviz
digraph add_entry{
rankdir=LR
node [shape=record]
indirect [
label="indirect"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
indirect -> node2:next [color=red]
head -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> NULL [tailclip=false]
}
```
3. After the second iteration, we can see that `indirect` points to `next` of the last node in the list (`node2` in this case), and it also matches the exit condition of the while loop (`*indirect` == `NULL`).
4. To append `new_node` to the list, we assign `new_node` to `*indirect`. So option `(b)` `*indirect = new_node` is the correct answer.
* **Before:**
```graphviz
digraph add_entry{
rankdir=LR
node [shape=record]
indirect [
label="indirect"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> *indirect == NULL }"
]
new_node [
xlabel="*(new_node)"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
indirect -> node2:next [color=red]
head -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next -> NULL [tailclip=false]
new_node:next:c -> NULL [tailclip=false]
}
```
* **After:**
```graphviz
digraph add_entry{
rankdir=LR
node [shape=record]
indirect [
label="indirect"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> *indirect == new_node }"
]
new_node [
xlabel="*(new_node)"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
indirect -> node2:next [color=red]
head -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next -> new_node [tailclip=false]
new_node:next:c -> NULL [tailclip=false]
}
```
:::success
Answer: `(b)` `*indirect = new_node`
:::
---
### Solutions to BB1 and BB2
* code snippet of `swap_pair`:
```c=
/* Swaps nodes in pairs
* e.g. {1, 2, 3, 4} => {2, 1, 4, 3} */
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;
}
```
#### BB1 = ?
* `(a)` `node = (*node)->next->next`
* `(b)` `*node = (*node)->next->next`
* `(c)` `*node = ((*node)->next)->next`
* `(d)` `*node = &((*node)->next)->next`
* `(e)` `node = &(*node)->next->next`
* `(f)` `*node = &(*node)->next->next`
#### BB2 = ?
* `(a)` `node = (*node)->next`
* `(b)` `node = &(*node)->next`
* `(c)` `*node = (*node)->next`
* `(d)` `*node = &(*node)->next`
* `(e)` `*node = &((*node)->next)`
:::info
**Idea**
1. We need a **cursor** with the type of `node_t**` to indicate the first node pair that we haven't swapped.
2. A temporary variable with the type of `node_t*` is required, and it is used for storing the address of one of the two nodes when swapping nodes in pairs.
:::
* pseudocode (single iteration):
```c=
BB2; /* points to the second node of the node pair */
tmp->next = (*node)->next; /* points to the first node of the "next" node pair */
(*node)->next = tmp; /* tmp points to the first node of the node pair */
BB1; /* lets node be able to find the first node of the "next" pair */
```
#### Implementation
1. Create a cursor (`node`) and a temporary variable (`tmp`):
```c
node_t **node = &head; /* line 5 */
node_t *tmp = *node; /* line 6 */
```
```graphviz
digraph swap_pair{
rankdir=LR
node [shape=record]
cursor [
label="node"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
tmp [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> head [color=red]
head -> node1 [color=blue]
tmp -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
2. Swap `node1` and `node2`:
* **BB2:** Point to the second node in the node pair.
```c
*node = (*node)->next; /* option (c) */
```
```graphviz
digraph swap_pair{
rankdir=LR
node [shape=record]
cursor [
label="node"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
tmp [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> head [color=red]
head -> node2 [color=blue]
tmp -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
* Point to the first node in the **next** node pair.
```c
tmp->next = (*node)->next; /* line 8 */
```
```graphviz
digraph swap_pair{
rankdir=LR
node [shape=record]
cursor [
label="node"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
tmp [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> head [color=red]
head -> node2 [color=blue]
tmp -> node1 [color=blue]
node1:next:c -> node3 [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
* Let `node2` point to `node1`.
```c
(*node)->next = tmp; /* line 9 */
```
```graphviz
digraph swap_pair{
rankdir=LR
node [shape=record]
cursor [
label="node"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
tmp [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> head [color=red]
head -> node2 [color=blue]
tmp -> node1 [color=blue]
node1:next:c -> node3 [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
3. **BB1:** Let `node` points to `node1.next`, which is the address of the first node in the next pair (`node3` in this case).
* `&node1.next`
=> `&node2.next->next`
=> `&head->next->next`
=> `&(*node)->next->next`
```c
node = &(*node)->next->next; /* option (e) */
```
```graphviz
digraph swap_pair{
rankdir=LR
node [shape=record]
cursor [
label="node"
shape=plaintext
fontcolor=red
]
head [
shape=plaintext
fontcolor=blue
]
tmp [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node1:next [color=red]
head -> node2 [color=blue]
tmp -> node1 [color=blue]
node1:next:c -> node3 [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
4. Repeat step 2 until all pairs are swapped.
5. Return the new `head`.
6. Done!
:::success
**Answer**
BB1: `(e)` `node = &(*node)->next->next`
BB2: `(c)` `*node = (*node)->next`
:::
---
### Solution to CCC
* code snippet of `reverse`:
```c=
/* Reverses the given list
* e.g. {1, 2, 3, 4} => {4, 3, 2, 1} */
node_t *reverse(node_t *head)
{
node_t *cursor = NULL;
while (head) {
node_t *next = head->next;
CCC;
head = next;
}
return cursor;
}
```
* **Before `reverse`:**
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
head -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
* **After `reverse`:**
```graphviz
digraph reverse{
rankdir=RL
node [shape=record]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
head -> node3 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> node2 [tailclip=false]
}
```
#### CCC = ?
* `(a)` `cursor = head; head->next = cursor`
* `(b)` `head->next = cursor; cursor = head`
* `(c)` `cursor = head`
* `(d)` `head->next = cursor`
* `(e)` `head->next->next = cursor; cursor->next = head`
* `(f)` `cursor->next = head; head->next->next = cursor`
:::info
**Idea**
1. Create a `cursor` that points to the previous node (points to `NULL` if the current node is the first node in the list).
2. Create a pointer called `next` that points to the next node (points to `NULL` if the current node is the last node in the list).
3. Let the current node point to the address that `cursor` points to.
4. Let `cursor` point to the current node.
5. Let `head` point to the next node.
:::
#### Implementation
1. Create a `cursor` that stores `NULL` first, and stores the address of the previous node in the following iterations:
```c
node_t *cursor = NULL;
```
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> NULL [color=blue]
head -> node1 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
2. Create a pointer called `next` that points to the next node (points to `NULL` if the current node is the last node in the list):
| current node | next node |
|:------------:|:---------:|
| `node1` | `node2` |
```clike
node_t *next = head->next;
```
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> NULL [color=blue]
head -> node1 [color=blue]
next -> node2 [color=blue]
node1:next:c -> node2 [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
3. **CCC:**
* Let the current node point to the address that `cursor` points to:
```clike
head->next = cursor; /* CCC part1 */
```
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> NULL [color=blue]
head -> node1 [color=blue]
next -> node2 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
* Let `cursor` point to the current node:
```clike
cursor = head; /* CCC part2 */
```
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node1 [color=blue]
head -> node1 [color=blue]
next -> node2 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
4. Let `head` point to the next node:
```clike
head = next;
```
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node1 [color=blue]
head -> node2 [color=blue]
next -> node2 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
5. Repeat **Step 2 ~ Step 4**:
| current node | next node |
|:------------:|:---------:|
| `node2` | `node3` |
* Let `next` point to the next node:
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node1 [color=blue]
head -> node2 [color=blue]
next -> node3 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node3 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
* Let the current node point to the address that `cursor` points to (`node1` in this case):
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node1 [color=blue]
head -> node2 [color=blue]
next -> node3 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
* Let `cursor` point to the current node:
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node2 [color=blue]
head -> node2 [color=blue]
next -> node3 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
* Let `head` point to the next node:
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node2 [color=blue]
head -> node3 [color=blue]
next -> node3 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
6. Repeat **Step 2 ~ Step 4**:
| current node | next node |
|:------------:|:---------:|
| `node3` | `NULL` |
* Let `next` point to the next node (`NULL` in this case):
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node2 [color=blue]
head -> node3 [color=blue]
next -> NULL [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> NULL [tailclip=false]
}
```
* Let the current node point to the address that `cursor` points to (`node2` in this case):
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node2 [color=blue]
head -> node3 [color=blue]
next -> NULL [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> node2 [tailclip=false]
}
```
* Let cursor point to the current node (`node3`):
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node3 [color=blue]
head -> node3 [color=blue]
next -> NULL [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> node2 [tailclip=false]
}
```
* Let `head` point to the next node (`NULL`):
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
shape=plaintext
fontcolor=blue
]
head [
shape=plaintext
fontcolor=blue
]
next [
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node3 [color=blue]
head -> NULL [color=blue]
next -> NULL [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> node2 [tailclip=false]
}
```
7. Return `cursor` as the new `head`:
```graphviz
digraph reverse{
rankdir=LR
node [shape=record]
cursor [
label="cursor\n(new head)"
shape=plaintext
fontcolor=blue
]
node1 [
xlabel="node1"
label="{ <value> | <next> }"
]
node2 [
xlabel="node2"
label="{ <value> | <next> }"
]
node3 [
xlabel="node3"
label="{ <value> | <next> }"
]
NULL [shape=plaintext]
cursor -> node3 [color=blue]
node1:next:c -> NULL [tailclip=false]
node2:next:c -> node1 [tailclip=false]
node3:next:c -> node2 [tailclip=false]
}
```
8. Done!
::: success
Answer: `(b)` `head->next = cursor; cursor = head`
:::
---
### Side Questions
1. Explain how other SLL operations work:
* **`find_entry`**: finds a specific node and returns its address
```c=
node_t *find_entry(node_t *head, int value)
{
node_t *current = head;
for (; current && current->value != value; current = current->next)
/* iterate */;
return current;
}
```
* **`remove_entry`**: removes a specific node and frees its memory by using pointer to a pointer
```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);
}
```
* **`print_list`**: prints all the nodes in the list
```c=
void print_list(node_t *head)
{
for (node_t *current = head; current; current = current->next)
printf("%d ", current->value);
printf("\n");
}
```
2. Change the return type of `swap_pair` and `reverse` from `node_t*` to `void`:
* **`swap_pair`**
```c=
/* Before */
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;
}
int main() {
...
head = swap_pair(head);
...
}
```
```c=
/* After */
void swap_pair(node_t **indirect)
{
for (node_t **node = indirect; *node && (*node)->next; node = &(*node)->next->next) {
node_t *tmp = *node;
*node = (*node)->next;
tmp->next = (*node)->next;
(*node)->next = tmp;
}
}
int main() {
...
swap_pair(&head);
...
}
```
* **`reverse`**
```c=
/* Before */
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;
}
int main() {
...
head = reverse(head);
...
}
```
```c=
/* After */
void reverse(node_t **indirect)
{
node_t *cursor = NULL;
while (*indirect) {
node_t *next = (*indirect)->next;
(*indirect)->next = cursor;
cursor = *indirect;
*indirect = next;
}
*indirect = cursor;
}
int main() {
...
reverse(&head);
...
}
```
3. Make **`reverse`** recursive:
```c=
/* Before */
void reverse(node_t **indirect)
{
node_t *cursor = NULL;
while (*indirect) {
node_t *next = (*indirect)->next;
(*indirect)->next = cursor;
cursor = *indirect;
*indirect = next;
}
*indirect = cursor;
}
```
```c=
/* After */
void reverse(node_t **indirect)
{
*indirect = rev_recursive(*indirect, NULL);
}
node_t *rev_recursive(node_t *current, node_t *prev) {
node_t *next = current->next;
current->next = prev;
if (!next)
return current;
return rev_recursive(next, current);
}
```
4. Implement [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) into SLL, and try to minimize the memory consumption:
```c=
#include <stdlib.h>
#include <time.h>
...
void fisher_yates_shuffle(node_t **head_address) {
int count = 0;
node_t **indirect = head_address;
/* Counts the number of nodes in the list */
while (*indirect) {
indirect = &(*indirect)->next;
count++;
}
node_t **node = malloc(sizeof(node_t*) * (count + 1));
indirect = head_address;
count = 0;
/* Stores the addresses of each node in the list */
while (*indirect) {
node[count++] = *indirect;
indirect = &(*indirect)->next;
}
node[count] = NULL;
/* Shuffles the addresses of each node */
for (int i = count - 1; i >= 1; i--) {
int target = rand() % (i + 1);
node_t *tmp = node[i];
node[i] = node[target];
node[target] = tmp;
}
/* Reconnects each node */
for (int i = 0; i < count; i++)
node[i]->next = node[i + 1];
/* Updates head */
*head_address = node[0];
free(node);
}
int main() {
srand(time(NULL));
...
fisher_yates_shuffle(&head);
...
}
```