运用掌握的数据结构,设计和实现一个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 = keyself.value = valueself.prev = Noneself.next = Noneclass LRUCache:def __init__(self, capacity: int) -> None:self.cache = dict()# 使用伪头部和伪节点self.head = DLinkedNode()self.tail = DLinkedNode()self.head.next = self.tailself.tail.next = self.headself.capacity = capacityself.size = 0def get(self, key: int) -> int:if key not in self.cache:return -1# 如果key存在,先通过哈希表定位,再移动头部node = self.cache[key]self.moveToHead(node)return node.valuedef 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 += 1if self.size > self.capacity:# 如果超出容量,删除双向链表的尾部节点removed = self.removeTail()# 删除哈希表中对应的项self.cache.pop(removed.key)self.size -= 1else:# 如果key存在,先通过哈希表定位,再修改value,并移到头部node = self.cache[key]node.value = valueself.moveToHead(node)def addToHead(self, node):# 头结点添加nodenode.prev = self.headnode.next = self.head.nextself.head.next.prev = nodeself.head.next = nodedef removeNode(self, node):# 双向链表删除数据node.prev.next = node.nextnode.next.prev = node.prevdef moveToHead(self, node):self.removeNode(node)self.addToHead(node)def removeTail(self):node = self.tail.prevself.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)
