# 2024q1 Homework2 (quiz1+2) contributed by < [han1018](https://github.com/Han1018) > ## 2024q1 第 1 週[測驗題](https://hackmd.io/@sysprog/linux2024-quiz2) ### 測驗一 測驗一用於實作非遞迴版本的 quick sort。 ```c node_t *begin[max_level], *end[max_level]; node_t *result = NULL, *left = NULL, *right = NULL; ``` begin[] 和 end[] 是堆疊,用來存儲比較的範圍。left 和 right 是用來存儲分割範圍後的左右子節點。 ```c node_t *L = begin[i], *R = end[i]; ``` 每一輪排序中,使用 L 和 R 來表示此輪要排序的串列的開頭和結尾。變數 i 用於指示目前要處理的未完成排序串列的位置。 ```c if (L != R) { node_t *pivot = L; value = pivot->value; node_t *p = pivot->next; pivot->next = NULL; while (p) { node_t *n = p; p = p->next list_add(n->value > value ? &right : &left, n); } ``` 用於比較的 Pivot 是從第一個元素取得的。用 p 來遍歷整個串列,將其與 pivot 的值進行比較,如果比 pivot 大就將其加入 right,如果小於等於就將其加入 left。 ```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); left = right = NULL; i += 2; ``` ### 測驗二 ## 2024q1 第 2 週[測驗題](https://hackmd.io/@sysprog/linux2024-quiz2) ### 測驗一 目標:程式中使用了 `order_node` 表示 preoreder 和 inorder 的排序,並要求回傳重建的二元樹。 - 結構體 `order_node` : 用於表示 inorder 和 preorder 的 雜湊鏈結串列 - `static int find(int num, int size, const struct hlist_head *heads)` : ```c if (num == on->val) return on->idx; } ``` 給定了一個 hash list_head 和指定的目標值,遍歷整個鏈結串列如果找到與目標值相同的 Node 回傳其 index。 - `static inline void node_add` : 用於建立雜湊鏈結串列,將 inorder 的 value 計算出雜湊值放置對應的位置。 - `static struct TreeNode *dfs` : 依據 inorder 和 preorder 還原二元樹 ```c tn->left = dfs(preorder, pre_low + 1, pre_low + (idx - in_low), inorder, in_low, idx - 1, in_heads, size); tn->right = dfs(preorder, pre_high - (in_high - idx - 1), pre_high, inorder, idx + 1, in_high, in_heads, size); ``` 根據 preorder 和 inorder 的特性找出 root、left、right node的過程如下: 1. 根據 preorder,第一個節點是根節點。 2. 根據 inorder,根節點的左邊是 left node,右邊是 right node。因此,可以遞迴地尋找 preorder 的 root,然後利用 root 找到 inorder 中左右兩節點的索引。接著,將這些索引套入遞迴中,以找出 preorder 的 root 、left 和 right node 的索引。 這樣的流程可以有效地根據 preorder 和 inorder 的特性來找出樹的結構。 - `static struct TreeNode *buildTree` : 還原二元樹的主流程: 1. 建立 鏈結串列雜湊表 2. 插入 inorder 的值至雜湊表 3. 用 preorder 和 inorder 比對找出左右根節點並建立二元樹 ### 測驗二 ```c typedef struct { int capacity; int count; struct list_head dhead; struct hlist_head hhead[]; } LRUCache; typedef struct { int key; int value; struct hlist_node node; struct list_head link; } LRUNode; ``` 實作中有兩個關鍵的結構體,一個是 LRUCache 另一個是 LRUNode。LRUCache 結構體中的雜湊表包含很多個 LRUNode ```c LRUCache *lRUCacheCreate(int capacity) ``` ```c LRUCache *cache = malloc(2 * sizeof(int) + sizeof(struct list_head) + capacity * sizeof(struct list_head)); ``` 這裡負責建立 LRUCache 結構體,上方 code 需修改為 capacity * sizeof(struct hlist_head)。 ```c void lRUCacheFree(LRUCache *obj) ``` 這裡負責移除和釋放 LRUCache,以及 LRUCache 中的所有 LRUNode。 ```c int lRUCacheGet(LRUCache *obj, int key) ``` 這裡負責從 LRUCache 中的雜湊表中檢索 key 的值並回傳。 ```c void lRUCachePut(LRUCache *obj, int key, int value) ``` 這裡負責將 key 和 value 加進 LRUCache 的雜湊表或是更新已經有 key 的值。 ### 測驗三 ```c static inline unsigned long __ffs(unsigned long word) ``` 這裡的任務是尋找第一個位元(bit),Num 記錄了第一位的位置。從32個位元中開始尋找,一直追蹤到最後一個位元。例如,如果 AAAA = 0xFFFFFFFF,則 num + 32,表示在2^32 -1之前的位元都不是第一個位元,因此向右移動32位,然後繼續尋找2^16,一直追蹤到經過63個位元後結束。 ```c static inline void __clear_bit(unsigned long nr, volatile unsigned long *addr) ``` 我們的目標是清除指定 mask 的值。addr 是要被清除的位址,nr 是一個 mask 用於清除 addr。清除的方法是 A &= ~mask,因為 mask 的值為1,將1反轉後再 and 就可以清除位元。因此 BBBB 是 ~mask。 ```c static inline unsigned long find_nth_bit(const unsigned long *addr, unsigned long size, unsigned long n) ``` 目標是找出記憶體區域中第 N 個被設為1的位元索引位置。在計算時,需要將 size 切分為多個 BITS_PER_LONG,然後使用 hweight_long 函數進行計算。