# 2023q1 Homework1 (quiz1)
contributed by < `chiacyu` >
# 測驗1
給定 [list.h](https://github.com/sysprog21/lab0-c/blob/master/list.h) 作為[〈linked list 和非連續記憶體操作〉](https://hackmd.io/@sysprog/c-linked-list)提及的 Linux 核心風格 circular doubly-linked list 實作,欲處理的節點採用以下結構體:
```c
#include <stdint.h>
#include "list.h"
struct item {
uint16_t i;
struct list_head list;
};
```
用以對節點內含值比較的函式:
```c
static inline int cmpint(const void *p1, const void *p2)
{
const uint16_t *i1 = (const uint16_t *) p1;
const uint16_t *i2 = (const uint16_t *) p2;
return *i1 - *i2;
}
```
以下程式碼實作快速排序法,數值由小到大排列,並確保可達到 [stable sorting](https://en.wikipedia.org/wiki/Sorting_algorithm) 的目標。
```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, AAA, BBB);
list_del(&pivot->list);
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);
}
list_sort(&list_less);
list_sort(&list_greater);
list_add(&pivot->list, head);
list_splice(&list_less, head);
FFF(&list_greater, head);
}
```
請補完,使其行為符合預期。作答規範:
`AAA` , `BBB` , `CCC` , `DDD` , `EEE` , `FFF` 應以最簡潔的形式撰寫,且符合作業一排版規範 (近似 Linux 核心程式碼排版風格),均不包含小括號 (即 ( 和 )),且不可出現 , 和 ; 這樣的分隔符號 (separator)
`BBB` 為 `identifier` , `CCC` , `DDD` , `EEE` , `FFF` 均為以 `list_` 開頭的巨集 (macro)
## 作答
### AAA & BBB
透過 [list.h](https://github.com/sysprog21/lab0-c/blob/master/list.h) 可以看到關於 `list_first_entry` 的說明
```
/**
* list_first_entry() - Get first entry of the list
* @head: pointer to the head of the list
* @type: type of the entry containing the list node
* @member: name of the list_head member variable in struct @type
*
* Return: @type pointer of first entry in list
*/
```
所以可以知道 `AAA = item` , `BBB = list`
### CCC & DDD & EEE
從程式的邏輯可以看出先取出 `queue` 中的第一個 `elements` 作為 `pivot` 並把他從原先的 `list` 裡面移除。 之後在走遍 `list` 裏面每一個 `element` 依照其 `i` 值,若比 `pivot` 小置於 `list_less` 反之則置於 `list_greater` 因此可知
- `CCC = list_for_each_entry_safe(itm, is, head, list)`
- `DDD = list_move_tail(&itm->list, &list_less)`
- `EEE = list_move_tail(&itm->list, &list_less)`
## 延伸問題
# 測驗 `2`
延續上方測驗 1,參考 [Optimized QuickSort — C Implementation (Non-Recursive)](https://alienryderflex.com/quicksort/),將以下程式碼改寫為非遞迴 (non-recursive; iterative) 的實作:
```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;
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);
}
HHHH (&pivot->list, &list_less);
if (!list_empty(&list_greater))
list_splice_tail(&list_greater, IIII);
if (!list_empty(&list_less))
list_splice_tail(&list_less, JJJJ);
} 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);
}
}
}
}
```
作答規範:
- 全部應以最簡潔的形式撰寫,避免空白字元
- `GGGG` 和 `HHHH` 都是以 `list_` 開頭的巨集
- `IIII`, `JJJJ`, `KKKK` 都包含 `stack`,並搭配必要的 C 運算子
## 作答
### GGGG & HHHH
- `GGGG = list_for_each_entry_safe (itm, is, &partition, list)`
- `HHHH = list_move_tail (&pivot->list, &list_less)`
### GGGG & HHHH & KKKK
- `IIII` = `&stack[++top]`
- `JJJJ` = `&stack[++top]`
- `KKKK` = `&stack[top--]`
在研究程式碼的時候花了很多時間來了閱讀[原文](https://alienryderflex.com/quicksort/)所用的方法。透過 `begin[]` 與 `end[]` 去紀錄尚未排序的陣列的 `L` 與 `R`。 在這邊的版本則是
首先先初始化一個 `stack[MAX_DEPTH]` 再將 `head` 放置於 `stack[0]` 。
取出第一個 `entry` 作為 `pivot` , 依序走遍整個鏈結,將小於 `pivot` 的節點插入 `list_less` ,大於 `pivot` 的節點插入 `list_greater`
接著將 `pivot` 插入 `list_little` 的尾部,分別將 `list_greater` 至於 `stack[1]` , `list_less` 放置於 `stack[2]` 。
直到 `top >= 0` && `list_is_singular(&stack[top])` 表示 `stack[top]` 只含有一個節點,再依序回收,串回 `head` 此時這些節點便已經排序好。
## 延伸問題
# 測驗 `3`
## 作答
### LLLL
從 `XOR_COMP()` 的結構來判斷,會將計算完的結果強制轉型成 `xor_node_t *` 。 從前文可以知道 `address` 計算的方式是透過 `XOR` 的特性所以可以知道:
`LLL = ((uintptr_t)a ^ (uintptr_t)b`)
#### MMMM