#2025q1 Homework2 (quiz1+2)
contributed by < Yuyuan1110 >
{%hackmd NrmQUGbRQWemgwPfhzXj6g %}
## 開發環境
```shell!
gcc --version
gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 39 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 16
On-line CPU(s) list: 0-15
Vendor ID: GenuineIntel
Model name: 12th Gen Intel(R) Core(TM) i5-1240P
CPU family: 6
Model: 154
Thread(s) per core: 2
Core(s) per socket: 12
Socket(s): 1
Stepping: 3
CPU(s) scaling MHz: 30%
CPU max MHz: 4400.0000
CPU min MHz: 400.0000
BogoMIPS: 4224.00
Virtualization: VT-x
Caches (sum of all):
L1d: 448 KiB (12 instances)
L1i: 640 KiB (12 instances)
L2: 9 MiB (6 instances)
L3: 12 MiB (1 instance)
NUMA:
NUMA node(s): 1
NUMA node0 CPU(s): 0-15
```
## 第一週測驗題
### [測驗題1](https://hackmd.io/@sysprog/linux2025-quiz1#%E6%B8%AC%E9%A9%97-1)
#### 補完 `list_insert_before` 函式
```clike!
list_insert_before(list_t *l, list_item_t *before, list_item_t *item){
list_item_t **p;
for (p = &l->head; *p != before; p = &(*p)->next)
;
*p = item;
item->next = before;
}
```
#### 程式碼運作原理
函式定義是將一個新元素插入到陣列中的指定元素之前。
可以看到函式內宣告了一個指向 `list_item_t` 類型的指標的間接指標 `p`,所以 for 迴圈當中的第一個條件應該要放入一個 `list_item_t` 類型的指標的地址值作為 for 迴圈的起始值。
當 `p` 中的值不等於 `before` 的時候條件成立,繼續走訪。
更新 `p` 中的 `list_item_t` 的指標為下個節點的指標位置。
#### 在現有的程式碼基礎上,撰寫合併排序操作
[完整程式碼](https://github.com/Yuyuan1110/linux-kernel-course-assignment/blob/master/week2/merge.h)
使用間接指標可以簡化當 `curr1 = NULL` 時的判斷,未使用間接指標時,會需要一個變數 `prev` 儲存 `curr1` 的最後一個元素,將 `prev->next` 指向 list2 剩餘的元素。
```clike!
void merge(struct list_t *list1, struct list_t *list2){
struct list_item_t **curr1 = &list1->head;
struct list_item_t *curr2 = list2->head;
while(*curr1 && curr2){
if((*curr1)->value > curr2->value){
temp = curr2->next;
list_insert_before(list1, *curr1, curr2);
if(*curr1 == list1->head){
list1->head = curr2;
}
curr2 = temp;
}else{
curr1 = &((*curr1)->next);
}
}
*curr1 = curr2;
list2->head = NULL;
}
```
#### 思考
Linux Kernel 風格的 linked list 的 header 是否可以當作一個指向第一個元素的指標的指標?
### [測驗題2](https://hackmd.io/@sysprog/linux2025-quiz1#%E6%B8%AC%E9%A9%97-2)
#### 補完程式碼
```clike!
while ((*pred_ptr)->r)
pred_ptr = &(*pred_ptr)->r;
```
### [測驗題3](https://hackmd.io/@sysprog/linux2025-quiz1#%E6%B8%AC%E9%A9%97-3)
#### 補完程式碼
```clike!
static void rebuild_list_link(struct list_head *head)
{
if (!head)
return;
struct list_head *node, *prev;
prev = head;
node = head->next;
while (node) {
node->prev = prev;
prev = node;
node = node->next;
}
prev->next = head;
head->prev=prev;/* GGGG */
}
```
```clike!
quick_sort(list_head *list){
int n = list_length(list);
int value;
int i = 0;
int max_level = 2 * n;
struct list_head *begin[max_level];
struct list_head *result = NULL, *left = NULL, *right = NULL;
begin[0] = list->next;
list->prev->next = NULL;
while (i >= 0) {
struct list_head *L = begin[i], *R = list_tail(begin[i]);
if (L != R) {
struct list_head *pivot = L;
value = list_entry(pivot,node_t,list)->value;/* HHHH */
struct list_head *p = pivot->next;
pivot->next = NULL; /* break the list */
while (p) {
struct list_head *n = p;
p = p->next;
int n_value = list_entry(n,node_t,list)->value;/* IIII */
if (n_value > value) {
n->next = right;
right = n;
} else {
n->next = left;
left = n;
}
}
begin[i] = left;
begin[i + 1] = pivot;/* JJJJ */
begin[i + 2] = right;/* KKKK */
left = right = NULL;
i += 2;
} else {
if (L) {
L->next = result;
result = L;
}
i--;
}
}
list->next = result;
rebuild_list_link(list);
}
```