bre*_*ett 10 c++ algorithm lru data-structures
我正在尝试使用C++实现LRU Cache.我想知道实现它们的最佳设计是什么.我知道LRU应该提供find(),添加一个元素并删除一个元素.删除应删除LRU元素.实现此目的的最佳ADT是什么?例如:如果我使用带有元素的映射作为值和时间计数器作为键我可以在O(logn)时间内搜索,Inserting是O(n),删除是O(logn).
Mat*_* M. 14
LRU缓存的一个主要问题是几乎没有"const"操作,大多数会改变底层表示(如果只是因为它们碰撞了访问的元素).
这当然非常不方便,因为它意味着它不是传统的STL容器,因此任何展示迭代器的想法都非常复杂:当迭代器被解除引用时,这是一个访问,它应该修改我们正在迭代的列表...天啊.
在速度和内存消耗方面都有性能考虑因素.
不幸的是,你需要一些方法来组织队列中的数据(LRU)(可以从中间删除元素),这意味着你的元素必须彼此独立.一std::list配合,当然,但它比你更需要.这里有一个单链表就足够了,因为你不需要向后迭代列表(毕竟你只想要一个队列).
然而,这些的一个主要缺点是它们的引用局部性较差,如果你需要更高的速度,你需要为节点提供自己的自定义(池?)分配器,以便它们尽可能保持紧密.这也将在一定程度上缓解堆碎片.
接下来,您显然需要一个索引结构(用于缓存位).最自然的是转向哈希映射.std::tr1::unordered_map,std::unordered_map或者boost::unordered_map通常是高质量的实施,有些应该可供您使用.他们还为哈希冲突处理分配额外的节点,您可能更喜欢其他类型的哈希映射,查看维基百科关于该主题的文章,并阅读各种实现技术的特征.
继续,有(明显的)线程支持.如果你不需要线程支持,那么没关系,如果你这样做,它会更复杂一些:
const这种结构几乎没有操作,因此您不需要区分读/写访问std::unique_ptr<Lock> lock()方法(在调试中,您可以断言,而不是在每个方法的入口点处进行锁定)最后,还有错误报告的问题.由于预计缓存可能无法检索您输入的数据,因此我会考虑使用"不良品味"的例外情况.考虑指针(Value*)或Boost.Optional(boost::optional<Value&>).我更喜欢Boost.Optional,因为它的语义清晰.
实现LRU的最佳方法是使用std :: list和stdext :: hash_map的组合(只想使用std然后std :: map).
这是你能得到的最快的,如果你使用的是hash_map,你几乎应该在O(1)中完成所有的操作.如果使用std :: map,它应该在所有情况下都需要O(logn).
这里有一个非常好的实现