我正在尝试使用C ++实现LRU Cache。我想知道什么是实现它们的最佳设计。我知道LRU应该提供find(),添加一个元素并删除一个元素。删除操作应删除LRU元素。最好的ADT是什么来实现的?例如:如果我使用一个元素为值且时间计数器为键的映射,则可以搜索O(logn)时间,插入为O(n),删除为O(logn)。
LRU高速缓存的一个主要问题是很少有“ const”操作,大多数操作都会更改基础表示(如果仅因为它们改变了所访问的元素)。
这当然很不方便,因为这意味着它不是传统的STL容器,因此任何展示迭代器的想法都非常复杂:取消引用迭代器时,这是一个访问权限,应修改我们要迭代的列表…天啊。
并且在速度和内存消耗方面都有性能方面的考虑。
不幸的是,但是您需要某种方式来将数据组织到队列(LRU)中(可以从中间删除元素),这意味着您的元素必须彼此独立。一std::list配合,当然,但比你需要更多。在这里,单链接列表就足够了,因为您不需要向后迭代列表(毕竟,您只需要一个队列)。
std::list
但是,这些方法的一个主要缺点是它们的引用局部性差,如果需要更高的速度,则需要为节点提供自己的自定义(pool?)分配器,以使它们尽可能地靠近。这也将在某种程度上减轻堆碎片。
接下来,您显然需要一个索引结构(用于缓存位)。最自然的是转向哈希表。std::tr1::unordered_map,std::unordered_map或者boost::unordered_map通常是高质量的实施方案,因此您应该可以使用某些方案。他们还为哈希冲突处理分配了额外的节点,您可能更喜欢其他种类的哈希图,查阅Wikipedia上有关该主题的文章,并了解各种实现技术的特征。
std::tr1::unordered_map
std::unordered_map
boost::unordered_map
继续,有(显而易见的)线程支持。如果不需要线程支持,那很好,但是如果需要,它会稍微复杂一些:
const
std::unique_ptr<Lock> lock()
最后,还有错误报告的问题。由于预期缓存可能无法检索您放入的数据,因此我将考虑使用“味道差”的异常。考虑指针(Value*)或Boost.Optional(boost::optional<Value&>)。我更喜欢Boost.Optional,因为它的语义很明确。
Value*
boost::optional<Value&>