您好,登录后才能下订单哦!
在计算机科学中,缓存是一种用于存储临时数据的技术,旨在提高数据访问速度。LRU(Least Recently Used,最近最少使用)是一种常见的缓存淘汰策略,它根据数据的历史访问记录来决定哪些数据应该被保留,哪些数据应该被淘汰。本文将详细分析LeetCode中LRU缓存机制的实现,并通过示例代码进行讲解。
LRU缓存是一种基于时间局部性原理的缓存策略。它假设最近被访问过的数据在未来被再次访问的概率较高,因此会优先保留这些数据。当缓存空间不足时,LRU缓存会淘汰最久未被访问的数据。
LRU缓存通常使用一个哈希表和一个双向链表来实现。哈希表用于快速查找缓存中的数据,而双向链表用于维护数据的访问顺序。具体来说:
当访问一个数据时,LRU缓存会执行以下操作:
LeetCode上有一道经典的LRU缓存问题,题目编号为146。题目要求实现一个LRU缓存类,支持以下操作:
LRUCache(int capacity)
:初始化缓存,capacity
表示缓存的最大容量。int get(int key)
:如果键key
存在于缓存中,则返回对应的值,否则返回-1。void put(int key, int value)
:如果键key
已经存在,则更新其对应的值;如果键不存在,则插入键值对。当缓存达到容量时,应该淘汰最久未使用的键值对。输入:
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出:
[null, null, null, 1, null, -1, null, -1, 3, 4]
解释:
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得键 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得键 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
为了实现LRU缓存,我们需要选择合适的数据结构。如前所述,哈希表和双向链表是常用的组合。
以下是使用Python实现的LRU缓存类:
class DLinkedNode:
def __init__(self, key=0, value=0):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.cache = {}
self.capacity = capacity
self.size = 0
self.head = DLinkedNode()
self.tail = DLinkedNode()
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key: int) -> int:
if key not in self.cache:
return -1
node = self.cache[key]
self.move_to_head(node)
return node.value
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
node.value = value
self.move_to_head(node)
else:
node = DLinkedNode(key, value)
self.cache[key] = node
self.add_to_head(node)
self.size += 1
if self.size > self.capacity:
removed = self.remove_tail()
del self.cache[removed.key]
self.size -= 1
def add_to_head(self, node):
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def remove_node(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def move_to_head(self, node):
self.remove_node(node)
self.add_to_head(node)
def remove_tail(self):
node = self.tail.prev
self.remove_node(node)
return node
__init__
方法:初始化缓存,设置容量,创建哈希表和双向链表的头尾节点。get
方法:如果键存在于缓存中,则将对应的节点移动到链表头部,并返回节点的值;否则返回-1。put
方法:如果键已经存在,则更新节点的值并将其移动到链表头部;如果键不存在,则创建新节点并插入到链表头部,同时更新哈希表。如果缓存已满,则删除链表尾部的节点,并从哈希表中移除对应的键。add_to_head
方法:将节点插入到链表头部。remove_node
方法:从链表中移除指定节点。move_to_head
方法:将指定节点移动到链表头部。remove_tail
方法:移除链表尾部的节点,并返回该节点。让我们通过一个具体的示例来分析LRU缓存的执行过程。
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
LRUCache(2)
,缓存容量为2。put(1, 1)
,缓存为{1=1}
。put(2, 2)
,缓存为{1=1, 2=2}
。get(1)
,返回1,并将键1移动到链表头部,缓存为{2=2, 1=1}
。put(3, 3)
,缓存已满,淘汰键2,缓存为{1=1, 3=3}
。get(2)
,返回-1,因为键2已被淘汰。put(4, 4)
,缓存已满,淘汰键1,缓存为{3=3, 4=4}
。get(1)
,返回-1,因为键1已被淘汰。get(3)
,返回3,并将键3移动到链表头部,缓存为{4=4, 3=3}
。get(4)
,返回4,并将键4移动到链表头部,缓存为{3=3, 4=4}
。[null, null, null, 1, null, -1, null, -1, 3, 4]
LRU缓存机制是一种高效的缓存淘汰策略,广泛应用于各种系统中。通过哈希表和双向链表的结合,我们可以实现一个时间复杂度为O(1)的LRU缓存。本文通过LeetCode中的LRU缓存问题,详细分析了LRU缓存的实现过程,并通过示例代码展示了其工作原理。希望本文能帮助读者更好地理解LRU缓存机制,并在实际开发中灵活运用。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。