linux2022
contributed by <ganoliz>
LeetCode編號1的題目 Two Sum,題意是給定一個陣列 nums 和一個目標值 target,求找到 nums 的 2 個元素相加會等於 target 的索引值。題目確保必為單一解,且回傳索引的順序沒差異。例如給定輸入 nums = [2, 7, 11, 15], target = 9,相加變成 9 的元素僅有 2 及 7,因此回傳這二個元素的索引值 [0, 1]。
以下是引入 hash table 的實作,學習 Linux 核心程式碼風格:
請補完程式碼。
AAA=?
BBB=?
延伸題目:
1.解釋上述程式碼運作原理
2.研讀 Linux 核心原始程式碼 include/linux/hashtable.h 及對應的文件 How does the kernel implements Hashtables?,解釋 hash table 的設計和實作手法,並留意到 tools/include/linux/hash.h 的 GOLDEN_RATIO_PRIME,探討其實作考量
首先我們先看看第一段程式碼:
明顯地,我們初始化一個 map , map 的大小以二的次方為單位, 使用 bits 做 bitwise 的位移,把我們 hash table 的第一個 list_head 的 first 指標設為 NULL 。 若 malloc 不成功就做一些必要的例外處置。
至於上面這段程式碼可以看到函數名稱是在做 hash 的動作。這個 GOLDEN_RATIO_32 我猜是一個比較不會發生碰撞的優良 hash 數值。 註解有提到,由於運算中高位元的數字變化通常比較隨機,因此 hash 出來的結果會從高位元位移,來產生出更好的 hash 數值。
這段是透過我們的先透過 hash function 運算找出在 hash table 的位置,透過其 head 分別對每個鏈結的 Node 走訪(為一個雙向鏈結串列,有 *next 與 **pprev )。當我們找到就回傳該 element ,若否則回傳 NULL 表示未找到。
第一個函數就是將剛剛 *find_key 找出來的 Node 往外回傳值。
第二個則是若這個 key 不存在 ,就新增此 key 到這個 hash table 位置的鏈結串列。
因此, AAA 應為 (c) n->next = first ,(因為等等要將 h->first 設為自己,所以 first 節點要變成串列的 Node )
而 BBB 應為 (a) n->pprev = &h->first (指向 first 的位置,目前為自己)。
針對 LeetCode 82. Remove Duplicates from Sorted List II,以下是可能的合法 C 程式實作:
請補完程式碼,COND1=? COND2=?
延伸問題:
1.嘗試避免遞迴,寫出同樣作用的程式碼
2.以類似 Linux 核心的 circular doubly-linked list 改寫,撰寫遞迴和迭代 (iterative) 的程式碼
根據程式碼,我們可以知道假如 COND1 通過的話, head 就會往前移動,反之 COND1 沒有通過的話, head 就會保留,然後對下個節點做 deleteDuplicates 。
因此,我們可以推測透過 COND1 是對目前節點是否為重複節點的判斷,因此我們假設:
當此條件成立時,就會進入 while() 迴圈來越過數個重複 value 的 node ,因此我認為
COND2 跟 COND1 可以是一樣的:
針對 LeetCode 146. LRU Cache,以下是 Least Recently Used (LRU) 可能的合法 C 程式實作:
請補完程式碼,注意作答規範:
延伸問題:
1.解釋上述程式碼的運作,撰寫完整的測試程式,指出其中可改進之處並實作
2.在 Linux 核心找出 LRU 相關程式碼並探討
MM1:
根據上面程式碼,我們可知 MM1 是走訪整個 LRUNode 的描述語句,因此我們回想一下 Linux Kernel API ,應該如此:
MM2:
MM2應為
MM3:
與MM2相同的程式碼 , MM3 與 MM2 的答案應該一致。
MM4:由程式碼判斷由 list_head dhead 找出 LRUNode 的位置,且根據前後程式碼說明空間已滿,所以我們踢出最後一個 LRUNode ,因此程式碼應為:
針對 LeetCode 128. Longest Consecutive Sequence,以下是可能的合法 C 程式實作:
請補完程式碼:
LLL=?
RRR=?
由於是找最長的數字串列(不用相鄰沒關係),於是這段程式使用 hash table 來實作。根據 num % 陣列 size 的值填入我們的 hash table 。所以要找尋特定 Node 的值就可以用 Find 來看看是否有出現在陣列中。 若有,就繼續往上跟往下找,並判斷目前的長度與之前搜索的長度進行比較,若比較則取代該值。若沒有則根據 for 迴圈對陣列索引加一,直到到達陣列索引最大值後返回最大的 Length 長度。
因此 LLL = (e) –left RRR= (c) ++right