如何设计最近最新使用的缓存?
假设您访问过某些项目。您需要设计一个数据结构来保存 这些项目。每个项目都与最近访问的时间相关联。
每次访问某个项目时,请在数据结构中进行检查。如果该项目已在缓存中,请更新其访问时间。否则,将其插入缓存中。高速缓存大小是固定的,如果已满,则删除最旧的项目。
我的解决方案:
使用地图< item,visitTime>
初始化:使用f(visitTime)按降序对地图进行排序。 O(nlg n)
如果访问了某个项目,请使用O(lg n)在地图中搜索该项目。
如果已在地图中,请更新时间O(1)。对地图O进行排序(lg N)。
如果没有,请将其插入地图然后排序。 O(lg n)
如果地图尺寸>固定大小,删除最后一个元素O(1)。
另一种解决方案:
使用哈希表< item,visitTime>
将其排序为O(n lgn)。
如果访问了某个项目,请使用O(1)在该项目中进行搜索。
如果已在表中,请更新时间O(1)。对表格进行排序 O(n lg n)。
如果没有,请将其插入表格然后排序。 O(n lg n)
如果表格大小>固定大小,删除最后一个元素O(1)。
有更好的解决方案吗?上) ?
答案 0 :(得分:4)
如果您使用双向链接列表,您将获得O(1)插入(搜索后),O(1)删除,O(n)搜索。
假设您在前面插入新项目:
如果缓存未满,只需添加到前面(O(1))。
如果您需要更新项目,找到它(O(n)),将其从链接列表中删除(O(1)),然后添加到前面(O(1))。
如果您需要删除最旧的项目以插入新项目,请删除结束元素(O(1)),然后插入前面(O(1))[注意:您需要先在此列表中搜索如果该项目尚未在缓存中,则为O(n)]。
链接列表也可以同时给你,因为搜索会让你离开最后一个元素。
答案 1 :(得分:3)
Python's LRU cache有O(1)插入,删除和搜索。它的设计使用一个双向链接的条目列表(排列最旧到最新)和一个哈希表来定位特定的链接。
这是一个简化(但很快)的版本,在40行非常基本的Python中。将Python的解决方案转换为C ++应该不难:
class LRU_Cache(object):
def __init__(self, original_function, maxsize=1000):
self.original_function = original_function
self.maxsize = maxsize
self.mapping = {}
PREV, NEXT, KEY, VALUE = 0, 1, 2, 3
self.head = [None, None, None, None] # oldest
self.tail = [self.head, None, None, None] # newest
self.head[NEXT] = self.tail
def __call__(self, *key):
PREV, NEXT, KEY, VALUE = 0, 1, 2, 3
mapping, head, tail = self.mapping, self.head, self.tail
sentinel = object()
link = mapping.get(key, sentinel)
if link is sentinel:
value = self.original_function(*key)
if len(mapping) >= self.maxsize:
oldest = head[NEXT]
next_oldest = oldest[NEXT]
head[NEXT] = next_oldest
next_oldest[PREV] = head
del mapping[oldest[KEY]]
last = tail[PREV]
link = [last, tail, key, value]
mapping[key] = last[NEXT] = tail[PREV] = link
else:
link_prev, link_next, key, value = link
link_prev[NEXT] = link_next
link_next[PREV] = link_prev
last = tail[PREV]
last[NEXT] = tail[PREV] = link
link[PREV] = last
link[NEXT] = tail
return value
if __name__ == '__main__':
p = LRU_Cache(ord, maxsize=3)
for c in 'abcdecaeaa':
print(c, p(c))
答案 2 :(得分:1)
使用两个共享相同数据的集合。有一个哈希表和一个列表。使用哈希表来验证项是否存在,并在列表中找到它(哈希映射的值是列表迭代器)。使用列表维护项目之间的顺序。同步两个集合(从列表中删除项目时,从哈希表中删除相应的项目)。列表迭代器必须是这样的,当你在列表中重新定位项时它不会改变。
编辑:std :: list iterator在添加和删除元素时有效,前提是迭代器引用的元素不会被删除。请参阅维基百科中Capacity and Allocation部分的最后几行。
答案 3 :(得分:1)
您可以使用java.util.LinkedHashSet在Java中执行此操作。它是一个与链表相结合的哈希表,它保留了项目的插入顺序。如果密钥扩散效果良好,您应该(预期)获得恒定的时间查找,插入和删除。
您可能还想查看实现自动机制的WeakHashMap,其中元素可以被垃圾收集。
答案 4 :(得分:0)
您不必对容器进行排序。只需将项目添加到地图或矢量中,然后线性地查看它以查找所需项目(或最旧的项目)。
然后它将是O(n)
。
答案 5 :(得分:0)
看看boost::multi_index。它显示的一个示例是MRU List。