# 2024q1 Homework2 (quiz1+2)
contributed by < `Grace258` >
- [第 1 週測驗題](https://hackmd.io/@sysprog/linux2024-quiz1)
- [第 2 週測驗題](https://hackmd.io/@sysprog/linux2024-quiz2)
---
## 測驗 `1`
實作非遞迴 `(non-recursive)` 的快速排序法,以 `swap` 為主體,利用 `L` 與 `R` 去紀錄需交換的數量,再用 `begin[]` 與 `end[]` 作為堆疊,用來紀錄比較的範圍。
### node_t *list_tail(node_t **left)
```cpp=
node_t *list_tail(node_t **left)
{
while ((*left) && (*left)->next)
left = &((*left)->next); //AAAA
return *left;
}
```
將 `*left` 移到鏈結串列的最後一個節點,因為使用 `indirect pointer` 所以要加上 `&` 取得指標的位址。
```graphviz
digraph nodes{
subgraph cluster_1{
style = invis
node1[label = "node1", shape = rect]
node2[label = "node2", shape = rect]
node3[label = "node3", shape = rect]
NULL[shape = plaintext]
{rank = same; node1->node2->node3->NULL}
}
left[label = "*left", shape = plaintext, fontcolor = green]
left->node3
}
```
```
#4 left = &((*left)->next);
```
---
### int list_length(node_t **left)
```cpp=
int list_length(node_t **left)
{
int n = 0;
while (*left) {
++n;
left = &((*left)->next); //BBBB
}
return n;
}
```
將 `*left` 移到鏈結串列的最後端 `(NULL)` ,因為使用 `indirect pointer` 所以要加上 `&` 取得指標的位址。
```graphviz
digraph nodes{
subgraph cluster_1{
style = invis
node1[label = "node1", shape = rect]
node2[label = "node2", shape = rect]
node3[label = "node3", shape = rect]
NULL[shape = plaintext]
{rank = same; node1->node2->node3->NULL}
}
left[label = "*left", shape = plaintext, fontcolor = green]
left->NULL
}
```
```
#6 left = &((*left)->next);
```
---
### void quick_sort(node_t **list)
```cpp=
void quick_sort(node_t **list)
{
int n = list_length(list);
int value;
int i = 0;
int max_level = 2 * n;
node_t *begin[max_level], *end[max_level];
node_t *result = NULL, *left = NULL, *right = NULL;
begin[0] = *list;
end[0] = list_tail(list);
while (i >= 0) {
node_t *L = begin[i], *R = end[i];
if (L != R) {
node_t *pivot = L;
value = pivot->value;
node_t *p = pivot->next;
pivot->next = NULL;
while (p) {
node_t *n = p;
p = p->next; //CCCC
list_add(n->value > value ? &right : &left, n);
}
begin[i] = left;
end[i] = list_tail(&left); //DDDD
begin[i + 1] = pivot;
end[i + 1] = pivot;
begin[i + 2] = right;
end[i + 2] = list_tail(&right); //EEEE
left = right = NULL;
i += 2;
} else {
if (L)
list_add(&result, L);
i--;
}
}
*list = result;
}
```
使用指標 `n` 走遍整個鏈結串列,將除了 `head/pivot` 節點的剩餘部分分成鏈結串列 `right` 和鏈結串列 `left` ,並將這三個鏈結串列的指標放入 `stack(begin 和 end)` 中。
```graphviz
digraph{
subgraph cluster_1{
style = invis
node0[label = 4, shape = rect]
node1[label = 1, shape = rect]
node5[label = 7, shape = rect]
node4[label = 2, shape = rect]
node3[label = 5, shape = rect]
node2[label = 3, shape = rect]
{rank = same; node5->node4->node3->node2}
}
head[label = "head", shape = plaintext, fontcolor = red]
pivot[label = "pivot", shape = plaintext, fontcolor = green]
left[label = "left", shape = plaintext, fontcolor = green]
right[label = "right", shape = plaintext, fontcolor = green]
head->node0
pivot->node0
left->node1
right->node5
}
```
將整個鏈結串列分成 `pivot` 、 `left` 、 `right` 三個部分( `left` 放小於 `pivot` 的節點, `right` 放大於 `pivot` 的節點)
```graphviz
digraph{
subgraph cluster_1{
style = invis
node0[label = 2, shape = rect]
node1[label = 5, shape = rect]
node2[label = 3, shape = rect]
node3[label = 7, shape = rect]
NULL[shape = plaintext]
{rank = same; node0->node1->node2}
}
pivot[label = "pivot", shape = plaintext, fontcolor = green]
left[label = "left", shape = plaintext, fontcolor = green]
right[label = "right", shape = plaintext, fontcolor = green]
pivot->node3
left->node0
right->NULL
}
```
```graphviz
digraph{
subgraph cluster_1{
style = invis
node0[label = 2, shape = rect]
node1[label = 5, shape = rect]
node2[label = 3, shape = rect]
NULL[shape = plaintext]
{rank = same; node1->node2}
}
pivot[label = "pivot", shape = plaintext, fontcolor = green]
left[label = "left", shape = plaintext, fontcolor = green]
right[label = "right", shape = plaintext, fontcolor = green]
pivot->node0
left->NULL
right->node1
}
```
```graphviz
digraph{
subgraph cluster_1{
style = invis
node0[label = 3, shape = rect]
node1[label = 5, shape = rect]
NULL[shape = plaintext]
}
pivot[label = "pivot", shape = plaintext, fontcolor = green]
left[label = "left", shape = plaintext, fontcolor = green]
right[label = "right", shape = plaintext, fontcolor = green]
pivot->node1
left->node0
right->NULL
}
```
重複執行直到 `left` 、 `right` 、`pivot` 都排序完畢。
### 改進方案
```cpp=
void quick_sort(struct list_head *head) {
if (list_empty(head) || list_is_singular(head))
return;
struct list_head *pivot = list_entry(head->prev, struct list_head, list);
struct list_head *left_list, *right_list;
INIT_LIST_HEAD(&left_list);
INIT_LIST_HEAD(&right_list);
struct list_head *pos, *q, *entry;
list_for_each_safe(pos, q, head) {
struct list_head *tmp = list_entry(pos, struct list_head, list);
if (tmp != pivot) {
list_del(pos);
INIT_LIST_HEAD(pos);
if (tmp->value < pivot->value){
list_for_each_entry(entry, left_list, list) {
if (tmp->value < entry->value) {
list_add_tail(&tmp->list, &entry->list);
return;
}
}
list_add_tail(&tmp->list, &left_list);
}
else{
list_for_each_entry(entry, right_list, list) {
if (tmp->value < entry->value) {
list_add_tail(&tmp->list, &entry->list);
return;
}
}
list_add_tail(&tmp->list, &right_list);
}
}
}
quick_sort(&left_list);
quick_sort(&right_list);
list_splice_tail(&left_list, head);
list_add_tail(&pivot->list, head);
}
```
## 測驗 `2` `Timsort`