# 2024q1 Homework2 (quiz1+2)
contributd by < `MiohitoKiri5474` >
## Quiz 1
### 測驗一
#### `AAAA`
`list_tail` 使用間接指標來操作,`left` 需要向後迭代,因此 `AAAA` 會被還原成 `(*left)->next`。
```c
while ((*left) && (*left)->next)
left = &((*left)->next);
return *left;
```
#### `BBBB`
`list_length` 同樣使用間接指標,用來查找整個 linked list 中的長度,當中的 `left` 需要向後迭代,因此 `BBBB` 同樣被還原成 `(*left)->next`。
```c
while (*left) {
++n;
left = &((*left)->next);
}
```
#### `CCCC`
`quick_sort` 以每個區間的第一個元素作為 pivot,且按照 Quick Sort 的排序方式,會將剩餘元素中比 pivot 小者放到 pivot 左邊、比 pivot 大者放到 pivot 右邊,因此這邊的 `CCCC` 會被還原成 `p->next`。
```c
while (p) {
node_t *n = p;
p = p->next;
list_add(n->value > value ? &right : &left, n );
}
```
接著會把放在左側的元素放在 `i`、pivot 放 `i + 1`、放在右邊的元素放在 `i + 2`,每次操作結束就會將 index += 2,並且在右側分割完畢後依序退回左側還沒分割的部分、並將已分割且排序好的元素放回 linked list 中保存。重複以上操作直到整個 list 排序完成。
#### `DDDD` & `EEEE`
`begin[]` 和 `end[]` 分別放 linked list 的開頭和結尾,照此邏輯 `DDDD` 和 `EEEE` 分別為 `list_tail(&left)` 和 `list_tail(&right)`
```c
begin[i] = left;
end[i] = list_tail(&left);
begin[i + 1] = pivot;
end[i + 1] = pivot;
begin[i + 2] = right;
end[i + 2] = list_tail(&right);
```
### 測驗二
#### `AAAA`
`merge()` 一樣也是間接指標,將 `&head` 填入 `AAAA`。
```c
struct list_head *head;
struct list_head **tail = &head;
```
#### `BBBB` & `CCCC`
經果比較 `a` 和 `b` 後,會將符合條件的節點加入 `tail` 中,並且將 `tail` 向後移動用以後續添加新的節點,因此 `BBBB` 和 `CCCC` 分別填入 `&a->next` 和 `&b->next`。
```c
if (cmp(priv, a, b) <= 0) {
*tail = a;
tail = &a->next;
a = a->next;
if (!a) {
*tail = b;
break;
}
} else {
*tail = b;
tail = &b->next;
b = b->next;
if (!b) {
*tail = a;
break;
}
}
```
#### `DDDD` & `EEEE`
這裡需要將 list 的關係建立好,行成環狀的 linked list。
因此 `DDDD` 和 `EEEE` 為 `tail->next` 和 `head->prev`。
```c
tail->next = head;
head->prev = tail;
```
#### `FFFF`
在經過最後一次合併時,需要將頭尾連接上形成環狀的 linked list。
因此在堆疊大小小於等於 1 的時候做此操作,`FFFF` 的值為 1。
```c
if (stk_size <= FFFF) {
build_prev_link(head, head, stk0);
return;
}
```
## Quiz 2
### 測驗一
#### `AAAA`
將節點加入到原本的開頭,所以需要將 `n->next` 設為 `h->first`(`AAAA`)。
```c
if (h->first)
h->first->pprev = &n->next;
n->next = h->first;
n->pprev = &h->first;
h->frst = n;
```
#### `BBBB` & `CCCC`
為了將指定 hash value 中相同的元素都取出,所以 `hlist_for_each` 開始的起點(`BBBB`)為 `&heads[hash]`
同時為了取得節點的資訊,需要用 `container_of`(或是 `list_entry`)取得。
```c
struct hlist_node *p;
int hash = (num < 0 ? -num : num) % size;
hlist_for_each (p, &heads[hash]) {
struct order_node *on = container_of(p, struct order_node, node);
if (num == on->val)
return on->idx;
}
```
#### `DDDD`
為了將新的元素加入對應 hash value 的欄位中,`DDDD` 應為 `&heads[hash]`。
```c
struct order_node *on = malloc(sizeof(*on));
on->val = val;
on->idx = idx;
int hash = (val < 0 ? -val : val) % size;
hlist_add_head(&on->node, &heads[hash]);
```
### 測驗二
#### `EEEE`
第一個 `pprev` 指向 `NULL` 的狀況不存在,因此可以將前一項與後一項相接。`EEEE` 為 `next->prev`。
```c
struct hlist_node *next = n->next, **pprev = n->pprev;
*pprev = next;
if (next)
next->prev = pprev;
```
#### `FFFF` & `GGGG`
為了將 `list_head` 中的節點都刪除,`pos` 在 `LRUNode` 結構中的名稱為 `link`,因此 `FFFF` 應該為 link。
而要將這個節點從 linked list 中移除,則需要刪除 `GGGG` 也就是 `&cache->link` 在 linked list 中的關係。
```c
struct list_head *pos, *n;
list_for_each_safe (pos, n, &obj->dhead) {
LRUNode *cache = list_entry(pos, LRUNode, link);
list_del(&cache->link);
free(cache);
}
free(obj);
```
#### `IIII`
要移動節點於 linked list 中的位置,`IIII` 需為 `&cache->link`。
```c
int hash = key % obj->capacity;
struct hlist_node *pos;
hlist_for_each (pos, &obj->hhead[hash]) {
LRUNode *cache = list_entry(pos, LRUNode, HHHH);
if (cache->key == key) {
list_move(&cache->link, &obj->dhead);
return cache->value;
}
}
```
#### `JJJJ` & `KKKK`
同理,為了將 `hlist_node` 中的節點移動位置,需要將其從 `LRUNode` 結構中取出,而他的名稱為 `node`(`JJJJ`)。
而 `KKKK` 則為 `&c->link`。
```c
LRUNode *cache = NULL;
int hash = key % obj->capacity;
struct hlist_node *pos;
hlist_for_each (pos, &obj->hhead[hash]) {
LRUNode *c = list_entry(pos, LRUNode, node);
if (c->key == key) {
list_move(KKKK, &obj->dhead);
cache = c;
}
}
```
### 測驗三
#### `AAAA`
這邊是採用二分艘,所以 `AAAA` 應該為 `0xffffffff`。
```c
if ((word & 0xffffffff) == 0) {
num += 32;
word >>= 32;
}
```
#### `BBBB`
藉由位元運算將指定位置的 bit 移除掉,具體作法是先產生一個在指定 bit 為 1 的 `mask`,並且將目前的值與 `~mask` 以 `and` 運算將此 bit 消除,因此 `BBBB` 為 `~mask`。
```c
static inline void __clear_bit(unsigned long nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *) addr) + BIT_WORD(nr);
*p &= ~mask;
}
```
#### `CCCC`
這邊是為了避免超出位數,所以是用 `%` 來運算。
```c
if (sz % BITS_PER_LONG) \
tmp = (FETCH) & BITMAP_LAST_WORD_MASK(sz); \
```