1.普通LRU实现
原题链接:LRU 缓存
python
class Node:
__slots__ = "prev", "next", "key", "value"
def __init__(self, key = 0, value = None):
self.key = key
self.value = value
class LRUCache:
def __init__(self, c):
self.c = c
self.h = {}
self.dummy = Node()
self.dummy.next = self.dummy
self.dummy.prev = self.dummy
def _remove(self, x):
x.prev.next = x.next
x.next.prev = x.prev
def _put_front(self, x):
x.next = self.dummy.next
x.prev = self.dummy
self.dummy.next.prev = x
self.dummy.next = x
def _get_node(self, key):
if key not in self.h: return None
x = self.h[key]
self._remove(x)
self._put_front(x)
return x
def get(self, key):
x = self._get_node(key)
return x.value if x else -1
def put(self, key, value):
x = self._get_node(key)
if x is not None:
x.value = value
self._remove(x)
self._put_front(x)
else:
x = Node(key, value)
self.h[key] = x
self._put_front(x)
if len(self.h) > self.c:
back = self.dummy.prev
del self.h[back.key]
self._remove(back)
对于实现的方法,我一般采取记忆方式防止漏写(比如_get_node中漏写return x等),下面数字代表几行代码哈哈哈哈。
- 复杂的方法共两个,
_get_node()和_put() _get_node():要记住 1(不在的情况) + 4 (在的情况)put(): 要记住3(不在的情况) + 3(在的情况) + 3(超容量的情况)
2.带TTL的LRU缓存
python
import time
class Node:
__slots__ = "prev", "next", "key", "value", "expire_time"
def __init__(self, key = 0, value = None, expire_time = 0):
self.key = key
self.value = value
self.expire_time = expire_time
class LRUCache:
def __init__(self, c, ttl):
self.c = c
self.ttl = ttl
self.h = {}
self.dummy = Node()
self.dummy.next = self.dummy
self.dummy.prev = self.dummy
def _remove(self, x):
x.prev.next = x.next
x.next.prev = x.prev
def _put_front(self, x):
x.next = self.dummy.next
x.prev = self.dummy
self.dummy.next.prev = x
self.dummy.next = x
# 新增一个函数
def _is_expired(self, x):
return time.time() > x.expire_time
def _get_node(self, key):
if key not in self.h:
return None
x = self.h[key]
if self._is_expired(x):
del self.h[key]
self._remove(x)
return None
self._remove(x)
self._put_front(x)
return x
def get(self, key):
x = self._get_node(key)
return x.value if x else -1
# 直接踢出末端的实现,几乎和普通LRU一致
def put(self, key, value):
x = self._get_node(key)
if x:
x.value = value
x.expire_time = time.time() + self.ttl # 就多了这一行
self._remove(x)
self._put_front(x)
else:
x = Node(key, value, time.time() + self.ttl)
self.h[key] = x
self._put_front(x)
if len(self.h) > self.c:
back = self.dummy.prev
del self.h[back.key]
self._remove(back)
# 先踢出过期的,如果没有踢出末端
def put(self, key, value):
x = self._get_node(key)
if x:
x.value = value
x.expire_time = time.time() + self.ttl
self._remove(x)
self._put_front(x)
else:
x = Node(key, value, time.time() + self.ttl)
self.h[key] = x
self._put_front(x)
if len(self.h) > self.c:
cur = self.dummy.prev
flag = False
while cur != self.dummy:
if self._is_expired(cur):
del self.h[cur.key]
self._remove(cur)
flag = True
break
cur = cur.prev
if not flag:
back = self.dummy.prev
del self.h[back.key]
self._remove(back)
同理,只要我们学会了普通LRU
_get_node():要记住 1(不在的情况) + 4 (在的情况) + 4(处理过期的情况)- 第1个
put(): 要记住4(不在的情况) + 3(在的情况) + 3(超容量的情况) - 第2个
put():要记住4(在的情况,多一个过期) + 3(不在的情况) + 3(超容量的情况2) + 超容量的情况1