手寫LRU
1.要求
- put / get 均是 O(1) 時間複雜度
- 超出容量自動刪除最老數據
2.用什麼數據結構?
- 任意查找要求 O(1),必然有哈希
-
時間需要有序,必然鏈表或者數組
- 由於刪除需求,也要控制在O(1),數組淘汰
- 由於單鏈表刪除節點,需要尋找前驅,並非 O(1),所以單鏈表淘汰
所以結論,哈希(key-->node) + 雙鏈表,哈希存key維持映射關係,雙鏈表維持時序以及val
3.進一步,鏈表的Node定義是?
-
初版
class Node(object): def __init__(self, v): self.val = v self.pre = None self.next = None 意思是3個字段:前驅、後繼、val
-
滿足需求嘛?
咋看是滿足需求的。val字段用來存儲值即可,前驅後繼也都滿足O(1)訴求
- 特例:當node超出容量時,每次新進一個節點,就需要淘汰鏈尾的節點(鏈尾的節點時間最久)
- 問題來了:鏈尾節點(val)刪除了,它對應的key還在哈希表裏,哈希表會有髒數據
- 結論:Node字段不足,還需要存儲key
-
Node定義的結論
class Node(object): def __init__(self, k, v): self.key = k self.val = v self.pre = None self.next = None 意思是4個字段:前驅、後繼、key, val
4.僞代碼
def get(key):
if key in hash:
將對應的節點提到雙鏈表表頭
return node.val
else:
return None
def put(key, val):
Node x = Node(key, val)
if key in hash:
將舊的節點從雙鏈表刪除
x節點插在雙鏈表表頭
else:
if cache is full:
刪除鏈尾節點
將鏈尾節點的key從hash刪除
x節點插入雙鏈表表頭
hash[key] = x節點