C++ implements LRU cache elimination mechanism

Introduction to caching

In order to speed up user access, we need to understand the caching algorithm. Common caching algorithms are:

  • LRU: (least recently used): It is rarely used recently and will not be eliminated first.
  • LFU (least frequently used): The least frequently used, the least frequently used will be eliminated first.
  • FIFO (first in first out): First in first out, the first in buffer is eliminated first.
    Today I mainly learned the LRU algorithm.

Introduction to LRU

LRU means that when the cache is full, if a new program is added, the one that has not been accessed for the longest time in the cache is erased from the cache, and then the new program is added to the first place in the cache. This program is now It is the most frequently accessed program.

Give a more common example. We first open WeChat, which is now running in the background, and then open QQ and Weibo.
At this time, the order of the software displayed in the background is: 1, Weibo 2, QQ 3, WeChat.
Assuming that this mobile phone can only run 3 programs in the background, when we turn on NetEase Cloud Music, the background will automatically close WeChat and put NetEase Cloud first.
The order of the background software at this time is: 1, NetEase Cloud 2, QQ 3, WeChat.

Realization principle

Requirement analysis:
1. The data structure required to be implemented is ordered ==> linked list
2. Fast search is required ==> hash table

So it is necessary to combine the advantages of these two and use the two structures together.
The structure of the design is as follows:

/*
 *双链表结点
 */ 
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();
 };

The above structure is to complete a double-linked list. The structure of the double-linked list is very efficient when inserting and deleting.
Then in order to improve the efficiency of the query, the unordered_map STL template is used here. This is equivalent to an unordered map, but the query efficiency is stable and higher than that of a map. For more details, please see: STL:unordered_map

The constructed cache structure is as follows:

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();
 };

Complete code

/*************************************************************************
	> 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();
}

Use list+unordered_map to see this great god: LRU cache

Guess you like

Origin blog.csdn.net/weixin_45146520/article/details/109078174