# 2023q1 Homework1 (quiz1)
contributed by < `csm1735` >
## 測驗 `1`
```c
if (list_empty(head) || list_is_singular(head))
return;
```
在一開始我們首先檢查串列是否為空或只有一個節點,如果是的話則不需要排序,因此直接 ```return```
```c
struct list_head list_less, list_greater;
INIT_LIST_HEAD(&list_less);
INIT_LIST_HEAD(&list_greater);
```
接著宣告了 ```list_less``` 和 ```list_greater``` ,並對其做初始化
```c
struct item *pivot = list_first_entry(head, AAA, BBB);
list_del(&pivot->list);
```
選擇第一個 entry 來做為 ```pivot``` ,並將其從原本的串列中刪除,我們可以看出 ```AAA``` 及 ```BBB``` 為 ```list_first_entry``` 所用到的兩個參數,而根據以下定義可知 ```AAA``` 為 struct 的型態, ```BBB``` 為成員的名稱。
```c
#define list_first_entry(head, type, member) \
list_entry((head)->next, type, member)
```
因此 ```AAA``` = ```struct item``` , ```BBB``` = ```list``` 。
```c
struct item *itm = NULL, *is = NULL;
CCC (itm, is, head, list) {
if (cmpint(&itm->i, &pivot->i) < 0)
DDD (&itm->list, &list_less);
else
EEE (&itm->list, &list_greater);
}
```
這段可看出 ```CCC``` 功能為走訪所有的節點來做比較的動作並移動,且根據其傳入的參數可判斷 ```CCC``` = ```list_for_each_entry_safe``` ,這樣的選擇可以允許目前的節點被移走,對於比較動作完成後的移動有所幫助,也因此 ```DDD``` 跟 ```EEE``` 皆為用來移動的 ```list_move_tail``` ,將值小於 ```pivot``` 的節點移到 ```list_less``` ,反之則移動到 ```list_greater``` ,值得一提的是,考量到為了使得排序達到 stable 的目標,所以在這邊 ```DDD``` 跟 ```EEE``` 不能選擇用 ```list_move``` 。
```c
list_sort(&list_less);
list_sort(&list_greater);
list_add(&pivot->list, head);
list_splice(&list_less, head);
FFF(&list_greater, head);
```
最後這邊,透過遞迴呼叫 ```list_sort``` 來將 ```list_less``` 和 ```list_greater``` 排序完成後,我們需要將```list_less``` 放在 ```pivot``` 之前,而```list_greater``` 放在 ```pivot``` 之後,所以 ```FFF``` 選擇使用 ```list_splice_tail``` ,這樣即完成排序。
---
## 測驗 `2`
```c
if (list_empty(head) || list_is_singular(head))
return;
```
在一開始我們首先檢查串列是否為空或只有一個節點,如果是的話則不需要排序,因此直接 ```return```
```c
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]);
```
宣告 stack ,並透過 ```INIT_LIST_HEAD``` 將其初始化,一開始先將 ```head``` 的節點全都移進 stack
```c
struct list_head partition;
INIT_LIST_HEAD(&partition);
while (top >= 0) {
INIT_LIST_HEAD(&partition);
list_splice_init(&stack[top--], &partition);
```
將 stack 中最頂端的 ```pop``` 出來放入 ```partition``` 中
```c
if (!list_empty(&partition) && !list_is_singular(&partition))
```
如果 ```partition``` 非空且不只一個節點則進行以下操作
```c
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);
```
這邊和測驗 1 類似,先宣告了 ```list_less``` 和 ```list_greater``` ,並對其做初始化,然後選擇 ```partition``` 中第一個 entry 來做為 ```pivot``` ,並將其從原本的串列中刪除。
```c
struct item *itm = NULL, *is = NULL;
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``` 功能為走訪所有的節點,且根據其傳入的參數可判斷 ```GGGG``` = ```list_for_each_entry_safe``` ,而這樣的選擇可以允許目前的節點被移走,對於比較判斷完成後的移動有所幫助,將值小於 ```pivot``` 的節點移到 ```list_less``` ,反之則移動到 ```list_greater``` 。
```c
HHHH (&pivot->list, &list_less);
```
我們會希望將```list_less``` 放在 ```pivot``` 之前,因此這邊 ```HHHH``` 選擇 ```list_move_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``` 做操作,由於尚未排序完成,我們是將其 push 進 stack 中,且為先推入大的 ```list_greater``` ,再推入小的 ```list_less``` 。
因此 ```IIII``` = ```JJJJ``` = ```&stack[++top]``` 。
```c
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(KKKK);
list_add_tail(&tmp->list, head);
}
}
```
如果 ```partition``` 只有一個節點則先將其 ```push``` 到 stack中。
然後如果 top 大於等於 0 且 ```stack[top]``` 只有單個節點,將該節點做移除的動作並 ```INIT_LIST_HEAD``` 然後再從 stack 中 pop 掉,因此 ```KKKK``` = ```&stack[top--]``` 。
而被移除的節點則加入 ```head``` 的尾端。
由以上觀察可發現,越小的節點越會到 stack 的頂端,也因此被移除的節點會是尚未被排序的節點中最小的,而透過將被移除的節點加入 ```head``` 尾端的作法,等同於將節點由小到大加入尾端,因此全部加入完畢時也就是排序完成。
---
## 測驗 `3`