运用掌握的数据结构,设计和实现一个LRU(最近最少使用)缓存机制。
LRU,Least Recently Used,即最近最少使用,是一种常用的页面置换算法。
LRU是操作系统为最大化页面命中率而广泛采用的一种页面置换算法。该算法的思路是,发生页面中断时,选择未使用时间最长的页面置换出去。
功能:
- 获取数据 get(key) - 如果关键字key存在于缓存中,则获取关键字的值,否则返回-1。
- 写入数据put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组。当缓存容量达到上限时,它应该再写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
分析
- 使用双向链表实现的队列,队列的最大容量为缓存的大小。在使用过程中,把最近使用的页面移动到队列头,最近没有使用的页面将被放在队列尾的位置。
- 使用一个哈希表,把页号作为键,把缓存在队列中的结点的地址作为值。
class DLinkedNode:
def __init__(self, key=0, value=0) -> None:
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int) -> None:
self.cache = dict()
# 使用伪头部和伪节点
self.head = DLinkedNode()
self.tail = DLinkedNode()
self.head.next = self.tail
self.tail.next = self.head
self.capacity = capacity
self.size = 0
def get(self, key: int) -> int:
if key not in self.cache:
return -1
# 如果key存在,先通过哈希表定位,再移动头部
node = self.cache[key]
self.moveToHead(node)
return node.value
def put(self, key: int, value: int) -> None:
if key not in self.cache:
# 如果key不存在,创建一个新的节点
node = DLinkedNode(key, value)
# 添加哈希表
self.cache[key] = node
# 添加至双向链表的头部
self.addToHead(node)
self.size += 1
if self.size > self.capacity:
# 如果超出容量,删除双向链表的尾部节点
removed = self.removeTail()
# 删除哈希表中对应的项
self.cache.pop(removed.key)
self.size -= 1
else:
# 如果key存在,先通过哈希表定位,再修改value,并移到头部
node = self.cache[key]
node.value = value
self.moveToHead(node)
def addToHead(self, node):
# 头结点添加node
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def removeNode(self, node):
# 双向链表删除数据
node.prev.next = node.next
node.next.prev = node.prev
def moveToHead(self, node):
self.removeNode(node)
self.addToHead(node)
def removeTail(self):
node = self.tail.prev
self.removeNode(node)
return node
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)