C++实现LRU缓存淘汰机制

缓存简介

为了加速用户的访问,我们需要了解缓存算法。常见的缓存算法有:

  • 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缓存

猜你喜欢

转载自blog.csdn.net/weixin_45146520/article/details/109078174