原文来自 http://www.hawstein.com/posts/lru-cache-impl.html
LRU算法的实现LRU的典型实现是hash map + doubly linked list, 双向链表用于存储数据结点,并且它是按照结点最近被使用的时间来存储的。 如果一个结点被访问了, 我们有理由
哈希表的作用是什么呢?如果没有哈希表,我们要访问某个结点,就需要顺序地一个个找, 时间复杂度是O(n)。使用哈希表可以让我们在O(1)的时间找到想要访问的结点, 或者返回未找到。
Cache主要有两个接口:
T Get(K key);
void Put(K key, T data);
当我们通过键值来访问类型为T的数据时,调用Get函数。如果键值为key的数据已经在 Cache中,那就返回该数据,同时将存储该数据的结点移到双向链表头部。 如果我们查询的数据不在Cache中,我们就可以通过Put接口将数据插入双向链表中。 如果此时的Cache还没满,那么我们将新结点插入到链表头部, 同时用哈希表保存结点的键值及结点地址对。如果Cache已经满了, 我们就将链表中的最后一个结点(注意不是尾结点)的内容替换为新内容, 然后移动到头部,更新哈希表。
#include <hash_map>
#include <vector>
using namespace stdext;
template <class K,class T>
struct Node
{
K key;
T data;
Node *pre,*next;
};
template <class K,class T>
class LRUCache
{
public:
LRUCache(size_t size)
{
entries_=new Node<K,T>[size];
for(int i=0;i<size;i++)
free_entries_.push_back(entries_+i);
head_=new Node<K,T>;
tail_=new Node<K,T>;
head_->pre=NULL;
head_->next=tail_;
tail_->pre=head_;
tail_->next=NULL;
}
~LRUCache()
{
delete head_;
delete tail_;
delete[] entries_;
}
void Put(K key,T data)
{
Node<K,T> *node=hashmap_[key];
if(node)
{
detach(node);
node->data=data;
attach(node);
}else
{
if(free_entries_.empty())
{
node=tail_->pre;
detach(node);
hashmap_.erase(node->key);
}else
{
node=free_entries_.back();
free_entries_.pop_back();
}
node->key=key;
node->data=data;
hashmap_[key]=node;
attach(node);
}
}
T Get(K key)
{
Node<K,T>* node=hashmap_[key];
if(node)
{
detach(node);
attach(node);
return node->data;
}else
{
return T();
}
}
void prin()
{
visit();
}
private:
//分离
void detach( Node<K,T>* node)
{
node->pre->next=node->next;
node->next->pre=node->pre;
}
//将节点插入头部
void attach(Node<K,T>* node)
{
node->pre=head_;
node->next=head_->next;
head_->next=node;
node->next->pre=node;
}
void visit()
{
Node<K,T> *p=head_->next;
while(p!=tail_)
{
cout<<p->data<<" "<<p->key<<endl;
p=p->next;
}
}
private:
hash_map<K, Node<K,T>* >hashmap_;
vector<Node<K,T>* > free_entries_;//存储可用节点的地址
Node<K,T> *head_,*tail_;
Node<K,T> *entries_;//双链表中的节点
};
int main()
{
LRUCache<int, string> lru_cache(2);
lru_cache.Put(1, "one");
cout<<lru_cache.Get(1)<<endl;
if(lru_cache.Get(2) == "")
lru_cache.Put(2, "two");
cout<<lru_cache.Get(2);
lru_cache.Put(3, "Three");
lru_cache.prin();
lru_cache.Put(4, "Four");
lru_cache.prin();
return 0;
}