您好,登录后才能下订单哦!
在计算机科学中,缓存是一种用于存储临时数据的技术,旨在提高数据访问速度。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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。