# 2021q1 Homework (quiz1)
contributed by < [`bakudr18`](https://github.com/bakudr18)>
###### tags: `linux2021`
> [第 1 週測驗題](https://hackmd.io/@sysprog/linux2021-quiz1)
## 測驗 `1`
* `LLL` = ?
`(c) left = &((*left)->next)`
`left` 型態為 pointer to pointer to `node_t` ,因此需先 dereference 成 `node_t*` 才可以操作 `next` ,最後 `left` 會指向 address of `next`。
* `AAA` = ?
`(e) &right`
因輸出結果須為 ascending order ,故比 `pivot->value` 大的 `node` 放在右邊,最後注意 `list_add_node_t` 傳入的參數型態為 `node_t**`。
* `BBB` = ?
`(c) &left`
反之,比 `pivot->value` 小的放左邊,理由同上。
* `CCC` = ?
`(b) list_concat(&result, pivot); list_concat(&result, right)`
因為 `pivot` < `right` ,先連結 `pivot` 後再連結 `right`。
## 解釋程式運作原理,搭配 Graphviz 解說
### Quick sort
quick sort 是一種 [divide-and-conquer algorithm](https://en.wikipedia.org/wiki/Divide-and-conquer_algorithm),先選擇一個 pivot ,然後比較各個 node 與 pivot 大小將 list 拆成 left 與 right , 分別對 left , right 排序後,再依據 left -> pivot -> right 順序重新串接。
```cpp
void quicksort(node_t **list)
{
if (!*list)
return;
node_t *pivot = *list;
int value = pivot->value;
node_t *p = pivot->next;
pivot->next = NULL;
node_t *left = NULL, *right = NULL;
while (p) {
node_t *n = p;
p = p->next;
list_add_node_t(n->value > value ? &right : &left, n);
}
quicksort(&left);
quicksort(&right);
node_t *result = NULL;
list_concat(&result, left);
list_concat(&result, pivot);
list_concat(&result, right);
*list = result;
}
```
一開始 `pivot` 會指向 `list` head。
```graphviz
digraph list {
node [shape=box];
list[shape=plaintext]
head[shape=plaintext]
pivot[shape=plaintext]
{
rank="same"
a [label="74"];
b [label="84"];
c [label="61"];
d [label="23"];
e [label="99"];
f [shape=plaintext label="NULL"];
}
{
a->b->c->d->e->f
}
{
list -> head -> a
pivot -> a
}
}
```
然後經過 `while(p)` 後會把 list 拆成 `left`, `right` 和 `pivot` 三組 list
```graphviz
digraph list {
node [shape=box];
pivot[shape=plaintext]
left[shape=plaintext]
right[shape=plaintext]
{
rank="same";
a [label="74"];
f [shape=plaintext label="NULL"];
a->f
}
pivot -> a
{
rank="same";
c [label="61"];
d [label="23"];
g [shape=plaintext label="NULL"];
d->c->g
}
left->d
{
rank="same";
b [label="84"];
e [label="99"];
h [shape=plaintext label="NULL"];
e->b->h
}
right->e
}
```
接著分別對 `left` , `right` 做 `quicksort`
```graphviz
digraph list {
node [shape=box];
pivot[shape=plaintext]
left[shape=plaintext]
right[shape=plaintext]
{
rank="same";
a [label="74"];
f [shape=plaintext label="NULL"];
a->f
}
pivot -> a
{
rank="same";
c [label="61"];
d [label="23"];
g [shape=plaintext label="NULL"];
d->c->g
}
left->d
{
rank="same";
b [label="84"];
e [label="99"];
h [shape=plaintext label="NULL"];
b->e->h
}
right->b
}
```
接著對 `left` 與 `pivot` 做 `list_concat`
```graphviz
digraph list {
node [shape=box];
result[shape=plaintext]
right[shape=plaintext]
{
rank="same";
a [label="74"];
c [label="61"];
d [label="23"];
g [shape=plaintext label="NULL"];
d->c->a->g
}
result->d
{
rank="same";
b [label="84"];
e [label="99"];
h [shape=plaintext label="NULL"];
b->e->h
}
right->b
}
```
最後再連結 `right`
```graphviz
digraph list {
node [shape=box];
result[shape=plaintext]
{
rank="same";
a [label="74"];
c [label="61"];
d [label="23"];
b [label="84"];
e [label="99"];
g [shape=plaintext label="NULL"];
d->c->a->b->e->g
}
result->d
}
```
## 引入其他 Pseudorandom number generator
#TODO
## 重寫 quick sort ,避免使用遞迴呼叫
使用 iterative 寫法勢必要自行維護 stack ,原作法已經可以將 `list` 拆分成 `left` , `pivot` , `right` 三段 linked-list,為了讓 stack top 的 `list` 是較小值的 `list` 以符合 ascending order , 因此推入順序會是 `right` 先,然後是 `pivot` ,最後是 `left`,然後在第二次迴圈繼續將 stack top 的 list 分段。 執行過程中的 stack 示意圖如下表示。
```
| | | |
| | |------------|
| | | subleft | <- sp
| | |------------|
| | | subpivot |
|-------| |------------|
| left | <- sp | subright |
|-------| |------------|
| pivot | | pivot |
|-------| |------------|
| right | | right |
--------- --------------
```
直到 stack top 的 sublist 只剩下一個 node 時,就代表這個 node 是 stack 中所有 node 中的最小值,此時才將 node 推入 result list 中。程式碼如下所示。
```c=
void quicksort(node_t **list)
{
#define MAX_LEVELS 600
node_t *stk[MAX_LEVELS];
node_t dummy;
node_t *tail = &dummy;
int sp = 0;
stk[sp] = *list;
while (sp >= 0) {
node_t *pivot = stk[sp--];
if (pivot->next) {
node_t *left = NULL;
node_t *right = NULL;
node_t *p = pivot->next;
pivot->next = NULL;
while (p) {
node_t *n = p;
p = p->next;
list_add_node_t(n->value > pivot->value ? &right : &left, n);
}
if (right)
stk[++sp] = right;
stk[++sp] = pivot;
if (left)
stk[++sp] = left;
} else {
tail->next = pivot;
tail = tail->next;
}
}
*list = dummy.next;
}
```