contributed by < [dcciou](https://github.com/dcciou) > # Q1第一題 ## AAAA,BBBB,CCCC 在 list_tail 和 list_length 函數中,我們需要找到方式來traverse鏈結串列。 AAAA: 由於 list_tail 函數需要traverse到串列的尾部,我們會繼續透過每個節點的 next 指標traverse。因此,AAAA 是 (*left)->next,即當前節點的下一個節點。 BBBB: 在 list_length 函數中,我們同樣需要traverse串列,計算長度。所以,BBBB 同樣是指向下一個節點的操作,即 (*left)->next。 CCCC: 在 quick_sort 中提到,當處理當前節點後,我們需要移動到下一個節點來繼續traverse。因此CCCC 是 p->next,表示從當前節點移動到下一個節點。 註:根據[資訊科技詞彙翻譯](https://hackmd.io/@sysprog/it-vocabulary),traverse翻成中文有超譯的情形,故採原文。 ## DDDD,EEEE DDDD 和 EEEE 代表在節點在跟pivot value比較後被分配到 left 或 right 之後,用於管理 left 和 right 分區末端邊界的操作。 各函數功能如下: list_add:將一個節點添加到列表的前面,並更新列表指向新添加的節點。 list_tail:找到列表中的最後一個節點,如果列表為空則回傳 NULL。 list_length:計算列表中節點的數量。 list_construct:創建一個新節點,並將其值設置為給定值,然後將其添加到列表的前面。 list_free:釋放列表中的所有節點。 考慮到這些函數的功能,DDDD 和 EEEE 的目的是: DDDD:在所有節點與pivot value比較後被分配給 left 分區之後,調用 list_tail 函數。這是因為我們需要找到 left 列表的最後一個節點,以正確設置 left 分區結束的邊界,才能開始對下一個分區進行排序。 因此答案為: ``` end[i] = list_tail(&left); ``` EEEE:同理,EEEE表示:在節點被分配到 right 分區之後,調用 list_tail 函數。在將節點分配給 right 列表後,找到其最後一個節點是必要的,以正確定義隨後對 right 側進行排序操作的邊界。 因此答案為: end[i + 2] = list_tail(&right); ## 延伸 # Q1第二題 &head &a -> next &b -> next # Q2第一題 ## 填空 AAAA: 將新節點加到 hlist的 頭部,故為 h->first BBBB: 利用 hash table 來找到每個數字的位置,一開始會從頭開始,故為 &heads[hash] CCCC: 這是一個 list_entry 的應用,它從 hlist_node 結構中取得包含它的 order_node 結構,故為 list_entry DDDD: 在 node_add 函式中,應該將新節點添加到對應 hash 值的 hlist_head 中,故為 &heads[hash]。 ## 延伸 # Q2第二題 ## 運作原理 使用一個 hash table(hhead)來快速定位緩存項目。 使用一個雙向鏈表(dhead)來追蹤訪問順序,表頭部分是最近訪問的項目,表尾部分是最久未訪問的項目。 當訪問一個項目時,如果項目存在於緩存中,它會被移動到雙向鏈表的頭部,表示它被最近訪問過。 當需要新增一個項目到緩存時,如果緩存已滿,則會移除雙向鏈表尾部的項目(最久未訪問),並將新項目插入到表頭。 每個緩存項目(LRUNode)都在雙向鏈表中有一個對應的結點(link),並且在hash table的相應位置有一個節點(node) ## 填空 EEEE: 在 hlist_del 函式中,需要設定下一個節點的 pprev 指標,指向前一個節點的 next 指標的地址,這是從雙向鏈表中刪除節點的一部分操作,故為 next->pprev。 FFFF: 在 lRUCacheFree 函式中,使用 list_entry 將 list_head 轉換為 LRUNode 結構,故為 link。 GGGG: 同上,這裡是刪除節點, list_del 用於將節點從雙向鏈表中移除,故為 &cache->link 。 HHHH: 在 lRUCacheGet 函式中,用 list_entry 將 hash list 節點轉換為 LRUNode 結構,以便能夠訪問 key value pair,故為 node 。 IIII: 這裡用 list_move 函式將節點移動到雙向鏈表的頭部,表示最近被訪問,故為 &cache->link 。 JJJJ: 在 lRUCachePut 函式中,同樣使用 list_entry 進行結構轉換,故為 node 。 KKKK: 將存在的節點移動到雙向鏈表頭部,或創建新節點並添加到鏈表頭部,故為 &c->link 。 # Q2第三題 ## 運作原理 __ffs 函數是尋找一個無符號長整型數字最低位的 1 的位元位置。這個函數假設至少有一位是設置為 1 的,因此在使用這個函數之前應該確保該數字不為 0。 __clear_bit 函數是用來清除(設為 0)無符號長整型數字中指定位置的位元。 fns 函數(Find Nth Set bit)是在給定的無符號長整型數字中找到第 N 個設置為 1 的位元位置。 find_nth_bit 函數是在一個記憶體區域中找到第 N 個設置為 1 的位元位置,如果沒有找到,則返回 size。 ## 填空 AAAA:此處我們需要用一個 16 進位的數來檢查 word 的前 32 位。在 64 位架構中,故為 0xffffffff。 BBBB:我們要用位元遮罩與原來的值進行 AND 操作來清除指定位元,所以我們需要 NOT mask (~mask)。 CCCC : 如果 sz 是 BITS_PER_LONG 的整數倍,則最後一個字中的所有位元都是有效的,我們不需要對最後讀取的字進行遮罩操作。反之,如果不是整數倍,那麼 sz % BITS_PER_LONG 將會給出非零的餘數,表示最後一個字中只有餘數那麼多位元是有效的,因此利用 % 來決定是否需要對最後一個字進行遮罩操作。