缓存简介
为了加速用户的访问,我们需要了解缓存算法。常见的缓存算法有:
- LRU: (least recently used) :最近很少使用,将不是最近用的先淘汰。
- LFU(least frequently used):最不经常使用,将最不经常用的先淘汰。
- FIFO(first in first out): 先进先出,先进缓存先淘汰。
今天主要是学习了LRU这个算法。
LRU简介
LRU就是当缓存满了的时候,若是再加入一个新的程序,就先将缓存里最久没访问那个从缓存中抹去,再将这个新的程序加入到缓存的第一位,这个程序现在是最常访问程序。
举一个比较常见的例子。我们先打开微信,此时微信就在后台运行了,再接着打开QQ和微博。
此时后台显示软件顺序就是:1、微博 2、QQ 3、微信。
假设这台手机后台只能运行3个程序,这时候我们再打开网易云音乐,后台会自动把微信给关闭,而把网易云提到第一位。
此时的后台软件顺序为:1、网易云 2、QQ 3、微信 。
实现原理
要求分析:
1、 要求实现的数据结构有顺序 ==> 链表
2、 要求查找快捷 ==> 哈希表
所以要结合这两个的优势,将两个结构结合在一起使用。
设计的结构入下:
/*
*双链表结点
*/
struct node{
int val,key;
node *prev,*next;
node():prev(NULL),next(NULL){
}
node(int k,int v):key(k),val(v),prev(NULL),next(NULL){
}
//重载 == 号
bool operator == (const node &p) const{
return val==p.val&&key==p.key;
}
};
/*
*双链表
*/
class DoubleList{
public:
node *first;
node *end;
int n;
DoubleList();
void addFirst(node*);//在第一个位置插入新元素
void remove(node*);//移除一个一定存在的节点
int removeLast();//移除最后一个节点
int size();
};
上面的结构是为了完成一个双链表。双链表的结构在插入删除时效率是很高的。
然后为了查询的效率提高,在这里使用 unordered_map 这个STL模板。这个相当于是无排序的map,但是查询效率稳定,比map要高,更多详情可以看:STL:unordered_map
所构建的缓存结构入下:
class LRUCache{
private:
unordered_map<int,node> map;
DoubleList *lru;
int maxSize;
public:
LRUCache(){
};
LRUCache(int ms);
int get(int key);
void put(int key,int val);
void show();
};
完整代码
/*************************************************************************
> File Name: lru.cpp
> Author:Ryan
> Mail:
> Created Time: Tue Oct 13 20:31:11 2020
> Function :实现LRU缓存淘汰策略
************************************************************************/
#include<iostream>
#include<unordered_map>
using namespace std;
/*
*双链表结点
*/
struct node{
int val,key;
node *prev,*next;
node():prev(NULL),next(NULL){
}
node(int k,int v):key(k),val(v),prev(NULL),next(NULL){
}
//重载 == 号
bool operator == (const node &p) const{
return val==p.val&&key==p.key;
}
};
/*
*双链表
*/
class DoubleList{
public:
node *first;
node *end;
int n;
DoubleList();
void addFirst(node*);
void remove(node*);
int removeLast();
int size();
};
/*
*构造函数,新建首尾节点,相连
*/
DoubleList::DoubleList(){
n=0;
first = new node();
end = new node();
first->next = end;
end->prev = first;
}
/*
*在第一位添加一个节点
*/
void DoubleList::addFirst(node *nd){
n++;
//node *tmp = new node(nd->key,nd>val);
node *t = first->next;
nd->next = t;
first->next = nd;
nd->prev = first;
t->prev = nd;
}
/*
*删除一个肯定存在的节点
*/
void DoubleList::remove(node *nd){
n--;
node *p = first;
while(p->key!=nd->key){
p=p->next;
}
node *pt = p->prev;
node *nt = p->next;
pt->next = nt;
nt->prev = pt;
delete p;
}
/*
*删除最后一个节点
*/
int DoubleList::removeLast(){
if(n>=1){
node *tmp = end->prev;
node *pt = tmp->prev;
pt->next = end;
end->prev = pt;
int t = tmp->key;
delete tmp;
n--;
return t;
}
return -1;
}
int DoubleList::size(){
return n;
}
class LRUCache{
private:
unordered_map<int,node> map;
DoubleList *lru;
int maxSize;
public:
LRUCache(){
};
LRUCache(int ms);
int get(int key);
void put(int key,int val);
void show();
};
LRUCache::LRUCache(int ms){
maxSize = ms;
lru = new DoubleList();
}
/*
*查找该节点
*/
int LRUCache::get(int key){
if(map.count(key)==0){
return -1;
}
else{
int val = map.find(key)->second.val;
put(key,val);
return val;
}
}
/*
*将节点提前
*/
void LRUCache::put(int key,int value){
node *nd = new node(key,value);
if(map.count(nd->key)==1){
//移到前面
lru->remove(nd);
lru->addFirst(nd);
}
else{
if(lru->n==maxSize){
int k = lru->removeLast();
map.erase(k);
lru->addFirst(nd);
}
else{
lru->addFirst(nd);
}
}
map[key] = *nd;
}
void LRUCache::show(){
if(lru->n==0) cout<<"empty task"<<endl;
else{
node *p = lru->first->next;
cout<<"当前一共有"<<lru->n<<"个任务: "<<endl;
for(int i=0;i<lru->n;i++){
cout<<"第"<<i+1<<"个任务: "<<p->val<<endl;
p=p->next;
}
}
}
int main(){
LRUCache *l = new LRUCache(3);
l->put(1,2);
l->put(2,3);
l->put(3,4);
l->put(4,5);
l->show();
}
使用list+unordered_map看这个大神 :LRU缓存