📜  使用 OrderedDict 在Python使用 LRU 缓存

📅  最后修改于: 2021-09-04 09:37:57             🧑  作者: Mango

LRU(最近最少使用)缓存首先丢弃最近最少使用的项目。该算法需要跟踪什么时候使用过,如果想要确保算法总是丢弃最近最少使用的项目,这会很昂贵。该技术的一般实现需要保留缓存行的“年龄位”并根据年龄位跟踪“最近最少使用”的缓存行。
我们的问题陈述是设计和实现最近最少使用 (LRU) 缓存的数据结构。
它应该支持以下操作:get 和 put。
* get(key) – 如果键存在于缓存中,则获取键的值(将始终为正),否则返回 -1。
* put(key, value) – 如果键不存在,则设置或插入值。当缓存达到其容量时,它应该在插入新项目之前使最近最少使用的项目无效。
缓存总是以正容量初始化。

例子:

Input/Output : 
LRUCache cache = new LRUCache( 2 /* capacity */ );

cache.put(1, 1);                                    
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4



我们的解决方案是使用集合模块中 OrderedDict 的强大功能,它保持键的插入顺序,如果需要,我们可以更改该顺序。最好的部分是所有操作的时间复杂度都是 O(1)。
我们以这样一种方式维护我们的 OrderedDict,即订单显示它们最近被使用的时间。一开始,我们将有最近最少使用的,最后是最近使用的。
如果对键进行任何更新或查询,它会移动到末尾(最近使用过)。如果添加了任何内容,则在最后添加(最近使用/添加)
对于 get(key):我们返回在 O(1) 中查询的键的值,如果在 out dict/cache 中没有找到键,则返回 -1。并且还将钥匙移到最后以显示它最近被使用过。
对于 put(key, value):首先,我们通过常规方法添加/更新键。并且还将钥匙移到最后以显示它最近被使用过。但是这里我们也会检查我们有序字典的长度是否超过了我们的容量,如果是,我们删除第一个键(最近最少使用)

Python3
from collections import OrderedDict
 
class LRUCache:
 
    # initialising capacity
    def __init__(self, capacity: int):
        self.cache = OrderedDict()
        self.capacity = capacity
 
    # we return the value of the key
    # that is queried in O(1) and return -1 if we
    # don't find the key in out dict / cache.
    # And also move the key to the end
    # to show that it was recently used.
    def get(self, key: int) -> int:
        if key not in self.cache:
            return -1
        else:
            self.cache.move_to_end(key)
            return self.cache[key]
 
    # first, we add / update the key by conventional methods.
    # And also move the key to the end to show that it was recently used.
    # But here we will also check whether the length of our
    # ordered dictionary has exceeded our capacity,
    # If so we remove the first key (least recently used)
    def put(self, key: int, value: int) -> None:
        self.cache[key] = value
        self.cache.move_to_end(key)
        if len(self.cache) > self.capacity:
            self.cache.popitem(last = False)
 
 
# RUNNER
# initializing our cache with the capacity of 2
cache = LRUCache(2)
 
 
cache.put(1, 1)
print(cache.cache)
cache.put(2, 2)
print(cache.cache)
cache.get(1)
print(cache.cache)
cache.put(3, 3)
print(cache.cache)
cache.get(2)
print(cache.cache)
cache.put(4, 4)
print(cache.cache)
cache.get(1)
print(cache.cache)
cache.get(3)
print(cache.cache)
cache.get(4)
print(cache.cache)
 
#This code was contributed by Sachin Negi


输出:
OrderedDict([(1, 1)])
OrderedDict([(1, 1), (2, 2)])
OrderedDict([(2, 2), (1, 1)])
OrderedDict([(1, 1), (3, 3)])
OrderedDict([(1, 1), (3, 3)])
OrderedDict([(3, 3), (4, 4)])
OrderedDict([(3, 3), (4, 4)])
OrderedDict([(4, 4), (3, 3)])
OrderedDict([(3, 3), (4, 4)])

时间复杂度:O(1)
LRU的其他实现