# 2023q1 Homework1 (quiz1)
contributed by < [willow11235811](https://github.com/willow11235811) >
## 測驗題目
:::danger
不用抄題目,闡述你的認知。
:notes: jserv
>已修改
:::
上述快速排序法,會將以 ```pivot``` 分割出數值較小的 ```list_less``` 與數值較大的 ```list_greater``` 。
```CCC``` 作用為依序走訪整個所有節點,應使用 ```list_for_each_entry_safe``` 。
用以對節點內含值比較的函式 ```cmpint``` 會比較 ```itm``` 和 ```pivot``` 的值,若 ```itm``` 較小,會回傳負值。
```DDD``` 應將較 ```pivot``` 小的節點移出並加入 ```list_less``` 中; ```EEE``` 則是處理相等或較大的節點。
因此 ```DDD``` 與 ```EEE``` 應為 ```list_move_tail``` ,將移出的節點附加到對應佇列的尾部。
```c
list_add(&pivot->list, head);
list_splice(&list_less, head);
FFF(&list_greater, head);
```
合併佇列時, ```list_add``` 將 ```pivot``` 節點加入 ```head``` 佇列的頭部。
```list_splice``` 將 ```list_less``` 黏貼至 ```pivot``` 節點之前,
因此 ```FFF``` 應為 ```list_splice_tail```,要將 ```list_greater``` 黏貼至 ```pivot``` 節點之後。
:::spoiler 測驗1 完整程式碼
```c
static void list_sort(struct list_head *head)
{
if (list_empty(head) || list_is_singular(head))
return;
struct list_head list_less, list_greater;
INIT_LIST_HEAD(&list_less);
INIT_LIST_HEAD(&list_greater);
struct item *pivot = list_first_entry(head, struct item, list);
list_del(&pivot->list);
struct item *itm = NULL, *is = NULL;
list_for_each_entry_safe (itm, is, head, list) {
if (cmpint(&itm->i, &pivot->i) < 0)
list_move_tail (&itm->list, &list_less);
else
list_move_tail (&itm->list, &list_greater);
}
list_sort(&list_less);
list_sort(&list_greater);
list_add(&pivot->list, head);
list_splice(&list_less, head);
list_splice_tail(&list_greater, head);
}
```
:::
---
## 測驗 2
```c
#define MAX_DEPTH 512
struct list_head stack[MAX_DEPTH];
```
利用 ```stack``` ,將程式改成迭代式的實作,但本實作能處理的節點數量顯然受限於 ```MAX_DEPTH``` 的大小。
```c
int top = -1;
list_splice_init(head, &stack[++top]);
```
首先,將欲處理的佇列經過 ```list_splice_init``` 接到 ```stack[0]``` 的頭部。
初始化 ```partition``` 作為處理待分割佇列的 ```list_head```。
```top``` 用以表示 ```stack``` 中還有多少佇列,也代表目前處理至 ```stack[top]``` 位置的佇列。
只要 ```top >= 0``` ,而且用以處理待分割佇列的 ```partition``` 中有兩個以上的節點,函式就要進行排序,直到 ```partition``` 中沒有或只剩一個節點。
```c
struct item *pivot =
list_first_entry(&partition, struct item, list);
list_del(&pivot->list);
INIT_LIST_HEAD(&pivot->list);
```
排序的方式是先把 ```partition``` 中的第一個節點 ```pivot``` 取出,作為排序比較的基準。
```c
GGGG (itm, is, &partition, list) {
list_del(&itm->list);
if (cmpint(&itm->i, &pivot->i) < 0)
list_move(&itm->list, &list_less);
else
list_move(&itm->list, &list_greater);
}
```
```GGGG``` 應為 ```list_for_each_entry_safe``` ,用以走訪整個 ```partition```。
將 ```pivot``` 以後的節點與 ```pivot``` 比較,較小者移動至 ```list_less``` 之頭部,較大者移動至 ```list_greater``` 的頭部。
```c
HHHH (&pivot->list, &list_less);
```
```pivot``` 也是需要處理的節點。
此處 ```HHHH``` 應為 ```list_add_tail``` ,將 ```pivot``` 加入 ```list_less``` 的尾部等待處理。
```c
if (!list_empty(&list_greater))
list_splice_tail(&list_greater, IIII);
if (!list_empty(&list_less))
list_splice_tail(&list_less, JJJJ);
```
接下來要將 ```list_greater``` 和 ```list_less``` 佇列依序連接至 ```stack``` 上,模擬遞迴呼叫。
```IIII``` 應為 ```stack[++top]``` , ```JJJJ``` 應為 ```stack[++top]```。
以第一次進入 ```while``` 迴圈為例,此時 ```top``` 值為 -1 ,利用 ```++top``` 將 ```top``` 值變為 0 ,即將 ```stack``` 佇列的第一個元素 ```stack[0]``` 作為插入 ```list_greater``` 的位置,並以同樣操作把 ```list_less``` 插入至 ```stack[1]``` 的位置。
此時 ```top``` 值為 1, 代表目前 ```stack``` 陣列中有 2 個排序後的佇列。
```c
list_splice_init(&stack[top--], &partition);
```
重新進入 ```while``` 迴圈,只要 ```top>=0``` ,就繼續對最尾部的 ```stack[top]``` 進行排序。
若這時 ```stack[top]``` 內只有一個元素,就會進入 ```else``` 的敘述。
```c
list_splice_tail(&partition, &stack[top]);
while (top >= 0 && list_is_singular(&stack[top])) {
struct item *tmp =
list_first_entry(&stack[top], struct item, list);
list_del(&tmp->list);
INIT_LIST_HEAD(KKKK);
list_add_tail(&tmp->list, head);
}
```
經過反覆的排序操作,排序後的佇列會由大至小的從 ```stack``` 的頭部向尾部分佈,此時 ```stack[top]``` 的元素為佇列中最小的元素。
將該元素以 ```list_del``` 自 ```stack[top]``` 佇列中刪除,並以 ```list_add_tail``` 加入 ```head``` 佇列中。
```KKKK``` 應為 ```stack[top--]``` ,將被取出元素的 ```stack[top]``` 初始化,並將 ```top``` 減一,更新目前 ```stack``` 陣列的元素數值。
反覆上述操作,最後 ```head``` 佇列為元素排序後的結果。
:::spoiler 測驗2 完整程式碼
```c
#define MAX_DEPTH 512
static void list_sort_nr(struct list_head *head)
{
if (list_empty(head) || list_is_singular(head))
return;
struct list_head stack[MAX_DEPTH];
for (int i = 0; i < MAX_DEPTH; i++)
INIT_LIST_HEAD(&stack[i]);
int top = -1;
list_splice_init(head, &stack[++top]);
struct list_head partition;
INIT_LIST_HEAD(&partition);
while (top >= 0) {
INIT_LIST_HEAD(&partition);
list_splice_init(&stack[top--], &partition);
if (!list_empty(&partition) && !list_is_singular(&partition)) {
struct list_head list_less, list_greater;
INIT_LIST_HEAD(&list_less);
INIT_LIST_HEAD(&list_greater);
struct item *pivot =
list_first_entry(&partition, struct item, list);
list_del(&pivot->list);
INIT_LIST_HEAD(&pivot->list);
struct item *itm = NULL, *is = NULL;
list_for_each_entry_safe (itm, is, &partition, list) {
list_del(&itm->list);
if (cmpint(&itm->i, &pivot->i) < 0)
list_move(&itm->list, &list_less);
else
list_move(&itm->list, &list_greater);
}
list_add_tail (&pivot->list, &list_less);
if (!list_empty(&list_greater))
list_splice_tail(&list_greater, stack[++top]);
if (!list_empty(&list_less))
list_splice_tail(&list_less, stack[++top]);
} else {
top++;
list_splice_tail(&partition, &stack[top]);
while (top >= 0 && list_is_singular(&stack[top])) {
struct item *tmp =
list_first_entry(&stack[top], struct item, list);
list_del(&tmp->list);
INIT_LIST_HEAD(stack[top--]);
list_add_tail(&tmp->list, head);
}
}
}
}
```
:::
---
## 測驗 3