C++ 如何使用STL实现LFU缓存?
我正在尝试使用纯STL实现LFU(使用频率最低的)缓存(我不想使用Boost!) 要求如下:C++ 如何使用STL实现LFU缓存?,c++,algorithm,caching,stl,C++,Algorithm,Caching,Stl,我正在尝试使用纯STL实现LFU(使用频率最低的)缓存(我不想使用Boost!) 要求如下: 使用键与std::map类似的对任何元素的关联访问 能够释放最低优先级的项目(使用其UsesCount属性) 能够更新任何项目的优先级(UsesCount) 问题是: 如果我使用std::vector作为项的容器(Key,Value,UsesCount),std::map作为向量的迭代器容器,用于关联访问和std::make_heap,std::push_heap和std::pop_heap作为向
- 使用
与键
类似的对任何元素的关联访问std::map
- 能够释放最低优先级的项目(使用其
属性)UsesCount
- 能够更新任何项目的优先级(
)UsesCount
- 如果我使用
作为项的容器(std::vector
,Key
,Value
),UsesCount
作为向量的迭代器容器,用于关联访问和std::map
,std::make_heap
和std::push_heap
作为向量内的优先级队列实现,堆操作后映射中的ITERTOR无效std::pop_heap
- 如果在以前的配置中使用
(或std::list
)而不是std::map
,std::vector
等,则无法编译,因为它们的迭代器不支持算术std::make_heap
- 如果我想使用
,我无法更新项目优先级std::priority\u queue
- 我是否遗漏了一些明显的问题,如何解决这个问题
- 你能给我举一个LFU缓存的纯C++/STL实现来满足以前的需求吗
感谢您的见解。您使用
*\u heap
函数和向量来实现似乎非常合适。尽管这会导致更新缓慢。对于使用向量作为底层数据结构的每个容器,遇到的迭代器失效问题是正常的。这也是所采用的方法,但由于上述原因,它没有提供可变接口。另一个提供了更新堆的能力
有些事情似乎有点奇怪:即使您能够使用std::priority\u queue
,您仍将面临迭代器失效问题
直接回答你的问题:你没有遗漏明显的东西<代码>标准::优先级_队列没有它应有的用处。最好的方法是编写支持更新的堆实现。要使其完全兼容STL(特别是分配器感知)是相当棘手的,而不是一项简单的任务。在此基础上,实现LFU缓存
对于第一步,请查看Boost实现以了解工作情况。我不知道第二个的任何参考实现
要解决迭代器失效问题,您可以选择间接到另一个容器中,尽管您应该尽量避免它,因为它会产生额外的成本,并且会变得非常混乱。这是一种比保留两个数据结构更简单的方法:
- 只需保留一个映射,它将您的键映射到它们的值/使用计数对
- 缓存已满时:
- 创建映射元素的迭代器向量(
)O(n)
- 创建映射元素的迭代器向量(
- 使用
查找最差的10%(std::nth_元素
)O(n)
- 使用
- 将它们全部从映射中删除(
)O(n日志n)
- 将它们全部从映射中删除(
O(logn)
,最坏情况下的O(nlogn)
,以及摊销后的O(logn)
在LFU缓存中删除最差的10%可能有点激烈,因为新条目必须达到前90%,否则将被删除。同样,如果只删除一个元素,那么在下一个新条目之前,新条目仍然需要从底部删除,否则它们会被剪切,这样做的时间就更少了。因此,取决于为什么LFU是适合您的正确缓存策略,我对它所做的更改可能是错误的策略,也可能仍然是正确的。“堆操作后映射中的ITERTOR无效”-通过另一种方式解决此问题--将数据放在
映射中,即使插入/擦除了其他元素,也不会移动。然后将映射迭代器放入向量中,并用它构建一个堆。不过,您可能仍然无法有效地更新项目的优先级,因此这不是答案。谢谢您提供了我没有想到的另一个想法。但是如果我有std::vector
的std::map
迭代器,我如何定义它们的比较运算符,它将在UsesCount
属性中查看指针对象的内部,要能够在项目插入后使用std::make_heap
或UsesCount
update来修复堆,请使用比较函数,如:bool operator()(MapIter a,MapIterB){return a->second.UseCountsecond.UseCount;}
仅在迂腐的一面,您肯定不是指最常用(MFU)/最近使用最少的(LRU)?使用频率最低的,为什么要缓存这些?引用维基百科的表格“LFU计算一个项目的需要频率。使用频率最低的项目首先被丢弃。”,这意味着这正是我想要的。如何使用*\u heap
更新优先级?我认为不仅仅是优先级队列
不能在这里完成工作:标准堆函数不能。因此提问者需要一个不同的堆实现。尽管我可能错了。@Steveop可能我错了,但在pri更新之后ority再次调用make_heap
应该可以修复堆。这可能远不是最佳的。同意。这将恢复堆不变量,但它是O(n)
。其他堆实现可以在O(log n)中增加/减少/更新
@SteveJessop我在答案中添加了一点,它变得更好了。@Blackhex:make\u heap
可以在每次更新时调用。它所做的只是在给定的范围内对元素重新排序。插入时不需要调用它,因为push\u heap
h