LRU Cache基本原理
Cache思想: 都是在给定一个限定大小的空间的前提下,设计一个原则如何来更新和访问其中元素
LRU算法设计原则:如何一个数据在最近一段时间没有被访问到,那么在将来他被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
现实中思维: 人类大脑存储的方式,例如,把人类大脑存储空间比作一个固定的大小的空间,存储的内存是电话号,总是能够先记住刚刚联系过的,而慢慢遗忘很久没有的访问的。
Cache应用场景:客户端访问的服务器的三层架构 内存------> 本地文件 --------->网络
Cache 数据结构:
map 数据结构 主要的作用是:用来存储数据
list 链表 主要的作用是:用来解决,删除的元素(次数最少访问的次数)
C++实现的代码
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
struct Node
{
int key;
int value;
Node *next;
};
class LRUCache{
private:
int count;
int size ;
map<int,Node *> mp;
Node *cacheList;
public:
LRUCache(int capacity) {
size = capacity;
cacheList = NULL;
count = 0;
}
int get(int key) {
if(cacheList==NULL)
return -1;
map<int,Node *>::iterator it=mp.find(key);
if(it==mp.end()) //如果在Cache中不存在该key, 则返回-1
{
return -1;
}
else
{
Node *p = it->second;
pushFront(p); //将节点p置于链表头部
}
return cacheList->value;
}
void set(int key, int value) {
if(cacheList==NULL) //如果链表为空,直接放在链表头部
{
cacheList = (Node *)malloc(sizeof(Node));
cacheList->key = key;
cacheList->value = value;
cacheList->next = NULL;
mp[key] = cacheList;
count++;
}
else //否则,在map中查找
{
map<int,Node *>::iterator it=mp.find(key);
if(it==mp.end()) //没有命中
{
if(count == size) //cache满了
{
Node * p = cacheList;
Node *pre = p;
while(p->next!=NULL)
{
pre = p;
p= p->next;
}
mp.erase(p->key);
count--;
if(pre==p) //说明只有一个节点
p=NULL;
else
pre->next = NULL;
free(p);
}
Node * newNode = (Node *)malloc(sizeof(Node));
newNode->key = key;
newNode->value = value;
newNode->next = cacheList;
cacheList = newNode;
mp[key] = cacheList;
count++;
}
else
{
Node *p = it->second;
p->value = value;
pushFront(p);
}
}
}
void pushFront(Node *cur) //单链表删除节点,并将节点移动链表头部,O(n)
{
if(count==1)
return;
if(cur==cacheList)
return;
Node *p = cacheList;
while(p->next!=cur)
{
p=p->next;
}
p->next = cur->next; //删除cur节点
cur->next = cacheList;
cacheList = cur;
}
void printCache(){
Node *p = cacheList;
while(p!=NULL)
{
cout<<p->key<<" ";
p=p->next;
}
cout<<endl;
}
};
int main(void)
{
/*LRUCache cache(3);
cache.set(2,10);
cache.printCache();
cache.set(1,11);
cache.printCache();
cache.set(2,12);
cache.printCache();
cache.set(1,13);
cache.printCache();
cache.set(2,14);
cache.printCache();
cache.set(3,15);
cache.printCache();
cache.set(4,100);
cache.printCache();
cout<<cache.get(2)<<endl;
cache.printCache();*/
LRUCache cache(2);
cout<<cache.get(2)<<endl;
cache.set(2,6);
cache.printCache(); //打印的KEY的值
cout<<cache.get(1)<<endl;
cache.set(1,5);
cache.printCache();
cache.set(1,2);
cache.printCache();
cout<<cache.get(1)<<endl;
cout<<cache.get(2)<<endl;
return 0;
}
上面的代码需要的改进的
1.因为需要经常要访问链表 -----因此需要使用双链表
2.因为map内部实现的方式是list这里每一次查找类似于 遍历一次链表,因此效率低,采用的方法:hash_map的线(确定 浪费空间)
参考资料
http://flychao88.iteye.com/blog/1977653