Python/LRU/LFU
自引用实现
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {}
self.root = [None, None, None, None] # 初始化哨兵节点,格式为 [prev, next, key, value]
self.root[:2] = [self.root, self.root] # 哨兵节点指向自己,形成循环
def _remove_node(self, node):
prev, next = node[0], node[1]
prev[1], next[0] = next, prev
def _add_to_front(self, node):
node[0] = self.root # node.prev = root
node[1] = self.root[1] # node.next = root.next
self.root[1][0] = node # root.next.prev = node
self.root[1] = node # root.next = node
def _move_to_front(self, node):
self._remove_node(node)
self._add_to_front(node)
def _pop_tail(self):
tail = self.root[0] # root.prev
self._remove_node(tail)
return tail
def get(self, key: int) -> int:
node = self.cache.get(key)
if not node:
return -1
self._move_to_front(node)
return node[3]
def put(self, key: int, value: int) -> None:
node = self.cache.get(key)
if not node:
new_node = [None, None, key, value] # [prev, next, key, value]
self.cache[key] = new_node
self._add_to_front(new_node)
if len(self.cache) > self.capacity:
# pop the tail
tail = self._pop_tail()
del self.cache[tail[2]] # tail.key
else:
# update
node[3] = value
self._move_to_front(node)
class DoublyLink:
def __init__(self):
self.root = [None]*5
self.root[:2] = [self.root, self.root]
self.size = 0
def append(self, node):
node[0], node[1] = self.root, self.root[1]
self.root[1][0] = node
self.root[1] = node
self.size += 1
def remove(self, node):
prev, next = node[:2]
prev[1], next[0] = next, prev
self.size -= 1
def pop(self):
if self.size == 0:
return None
node = self.root[0]
self.remove(node)
return node
class LFUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {}
self.frep_map = {}
self.min_freq = 0
def get(self, key: int) -> int:
node = self.cache.get(key)
if not node:
return -1
else:
self.update(node)
return node[3]
def put(self, key: int, value: int) -> None:
node = self.cache.get(key)
if node:
node[3] = value
self.update(node)
else:
node = [None,None,key,value,1]
if len(self.cache) == self.capacity:
self.evict()
self.cache[key] = node
self.min_freq = 1
if 1 not in self.frep_map:
self.frep_map[1] = DoublyLink()
self.frep_map[1].append(node)
def update(self, node):
freq = node[4]
self.frep_map[freq].remove(node)
if self.frep_map[freq].size == 0:
if self.min_freq == freq:
self.min_freq += 1
del self.frep_map[freq]
if freq+1 not in self.frep_map:
self.frep_map[freq+1] = DoublyLink()
self.frep_map[freq+1].append(node)
node[4] += 1
def evict(self):
node = self.frep_map[self.min_freq].pop()
del self.cache[node[2]]
if self.frep_map[self.min_freq].size == 0:
del self.frep_map[self.min_freq]
# Your LFUCache object will be instantiated and called as such:
# obj = LFUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)