1
Two Sum 以 Linux 核心風格的 hash table 解之參考 Linux 原始碼中 type.h :
map_t
裡的 hlist_head
array 當作 bucket,每個 bucket 裝有一串結構體:hash_key
,並由 hash_key
裡的 hlist_node
串起。1 << bits
代表可以有多少不同的十進制數字,也就是 hash table 有多少 bucket(hlist_head
[] size)。find_key
函式中,將 key 代入 hash 函式找出對應的 hash 值,來得到該 bucket(hlist_head
),再由 hlist_head->first
開始迭代 hlist_node
。container_of
找出 結構體 hash_key
地址,便可以找到該結構體的 key。第 7 行配置一個結構體空間:hash_key
,第 10 行找到該b ucket(hlist_head
):h
,第 11 行找到該新增的結構體裡的 hlist_node
:n
。
接下來要處理新增的 hlist_node
的 next
及 pprev
,新增的 hlist_node
會直接插入 bucket 的第一個位置, 因此將新增的 hlist_node->next
指向 hlist_head
現在的 first
,AAA
= n->next = first
。
第 13-15 行,若 hlist_head
裡有 hlist_node
,hlist_head
現在的 first->pprev
指向前一個元素的記憶體位址本身:&n->next
(為何不指向 &n?)。hlist_head
現在的 first
替換成新增的 hlist_node
。
新增的 hlist_node->pprev
指向前一個元素的記憶體位址本身,因此 BBB
= n->pprev = &h->first
(為何不指向 &h?)。
上述 highlight 處,我認為有可能的原因在於方便其他操作,如下方 map_deinit
函式裡第 18 行,只需 dereference pprev
就可以拿到指向下一個 node 的指標。
疑問:上述 highlight 處
TODO:
2
Remove Duplicates from Sorted List針對 LeetCode 82. Remove Duplicates from Sorted List II,以下是可能的合法 C 程式實作:
此遞迴函式的終止條件分成三部份:
當前節點為空時,回傳空節點。
當前節點的下個節點不為空,且當前節點的值等於下個節點的值,當前節點會往下迭代,如此可以跳過重複的節點。
回傳下個節點為首的 linked-list 。
所以 COND1
以及 COND2
= head->next && head->val == head->next->val
。
當前節點的下個節點不為空,且當前節點的值與下個節點的值不同,以當前節點的下個節點為首呼叫此遞迴函式,來刪掉下個節點為首的 linked list 裡重複的節點。
回傳當前節點為首的 linked-list 。
想法是迭代整個 linked list,只要遇到連續同樣值的節點,便將「出現同樣值的第一個節點」的 next
指向下下一個節點。
要注意的是需要移除所有重複的節點,所以「出現同樣值的第一個節點」也必需被移除。而這裡的 linked list 為單向,所以需要宣告新的變數來儲存前一個節點,來讓「出現同樣值的第一個節點」被其前節點跳過。
TODO:
3
LRU Cache針對 LeetCode 146. LRU Cache,以下是 Least Recently Used (LRU) 可能的合法 C 程式實作
補完程式碼 MMM1
, MMM2
, MMM3
, MMM4
,都是 Linux 核心風格的 list 巨集,以 list_ 開頭
以下為參考 jim12312321
且經消化過的內容
LRUCache
裡 hheads
有多大,也就是 LRUNode 的上限LRUNode
LRUNode
的 headLRUNode
的 headLRUNode
的編號LRUNode
的值hheads[hash值]
後面dhead
後面,越前面代表越近被使用過因為 hheads
是 array,得知 capacity 時需配置另外的空間。
INIT_LIST_HEAD
為將結點設為雙向鏈結串列。
MMM1
= list_for_each_entry_safe
,透過此 preprocessor directive 可以取得每個 LRUNode->dlink
的地址,其定義為:
entry:由 list_head
串起的主體,在這裡即 LRUNode
head:整串 list,在這裡即 LRUCache
的 dhead
採用 safe 的版本是因為需要存下一個 node 用以接著 delete
MMM2
= list_for_each_entry
,透過此可以取得 hlink
的地址,其作用為 list_for_each_entry_safe
沒有儲存下一個 node 的版本:
entry:由 list_head
串起的主體,在這裡即 LRUNode
head:整串 list,在這裡即 obj->hheads[hash值]
lRUCacheGet
目的在於依據 key
值,將對應的 LRUNode
取出,並透過 list_move
將此 LRUNode
移到 dhead
的開頭,代表目前最常被使用過。
MMM3
= list_for_each_entry
,解釋同MMM2
MMM4
= list_last_entry
,作用為取出整串 dhead
的最後一個 LRUNode->dlink
的地址,其定義為:
lRUCachePut
目的為當有找到對應 key
值的 LRUNode
時將其值取代,並將此 LRUNode
移到 dhead
的開頭,代表目前最常被使用過。
倘若 LRUCache
沒有空間時,利用 list_last_entry
刪掉 dhead
最後一個節點(代表目前最不常使用的)。若仍有空間,配置一個
LRUNode
的空間。最後更新 LRUNode
所需資訊。
TODO:
4
Longest Consecutive Sequence針對 LeetCode 128. Longest Consecutive Sequence,以下是可能的合法 C 程式實作:
根據程式碼畫出結構示意圖:
find
函式裡的參數 size
即為 heads
的大小。根據參數 num
做模餘對應到 hash 串列開頭,透過此串列(link
)逐一尋訪 seq_node
,試圖找到有著 num
的 seq_node
。
longestConsecutive
函式在開始時配置 n_size
的 heads
空間,並根據 nums
array 裡的值,逐一配置 seq_node
的空間再將其串在對應 hash 值的 heads
後。
最後一個 for loop 即在找尋nums
array 裡有幾個連續數值。迭代nums
array,將每個值連續相加及連續相減直到找不到相應值的 seq_node
為止,過程中將長度記下。且在找到相應值的 seq_node
時透過 list_del
將該 seq_node
的 link
從 heads
串列中移除,避免接下來的尋訪再次重複。
因為在此 for loop 中任意 nums
array 的值已經找過,接下來要分別往上及往下尋找,因此LLL
= --left
,RRR
= ++right
。
TODO: