手写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节点