LRU缓存淘汰算法

1.LRU算法介绍

缓存满了需要删除一些缓存,LRU(Least Recently Used)就是一种常用的策略,表示缓存数据的重要程度与最后一次使用时间有关,缓存满了,就先删除很久没有用过的缓存数据。

2.算法要求

leetcode例题icon-default.png?t=LA92https://leetcode-cn.com/problems/lru-cache/初始化构造函数需要接受一个capacity参数作为缓存最大容量。

put(key,val)方法存入键值对。

get(key,val)方法获取key对应的val,不存在则返回-1。

要求put和get的时间复杂度都为O(1),则LRUCache这个数据结构必备条件如下:

  1. LRUCache中的元素必须有时间顺序,容量满了可以直接删除未使用的元素。
  2. LRUCache能快速查找key对应的val。
  3. LRUCache能够在任意位置快速插入和删除元素。

3.数据结构设计

哈希表查询为O(1),但是键值对之间没有顺序,链表有顺序,插入删除快,但是查找慢。

LRU算法的核心就是哈希链表,是双向链表和哈希表的结合体。

  1.  每次默认从链表尾部添加元素,越靠近头部的元素就是越久没用的缓存。
  2. 对于一个key,可以通过哈希表快速定位到链表中的节点。
  3. 链表支持快速删除和插入,这里借助哈希表能快速查找到链表的节点。

4.代码实现

4.1 双向链表节点

struct Node{
    int key,val;
    Node* next;
    Node* prev;
    Node(int k,int v){
        this->key=k;
        this->val=v;
        this->next=nullptr;
        this->prev=nullptr;
    }
};

4.2 双向链表以及其操作

class DoubleList{
private:
    Node* DummyHead;
    Node* DummyTail;
    int _size;
public:
    DoubleList(){
        //初始化双向链表数据
        DummyHead=new Node(0,0);
        DummyTail=new Node(0,0);
        DummyHead->next=DummyTail;
        DummyTail->prev=DummyHead;
        _size=0;
    }
    void addLast(Node* x){
        //在链表最后添加节点,O(1)
        x->prev=DummyTail->prev;
        x->next=DummyTail;
        DummyTail->prev->next=x;
        DummyTail->prev=x;
        _size++;
    }
    void remove(Node* x){
        //删除列表中的节点
        x->prev->next=x->next;
        x->next->prev=x->prev;
        _size--;
    }
    Node* removeFirst(){
        //删除第一个节点,并返回。
        if(DummyHead->next == DummyTail){
            return nullptr;
        }
        Node* first=DummyHead->next;
        remove(first);
        return first;
    }
    int size(){
        return _size;
    }
    
};

 4.3 LRUCache

其中省略哈希表的具体实现,借用STL中的unordered_map

class LRUCache {
private:
    unordered_map <int,Node*>map;
    DoubleList *cache;
    int capacity;
    /*
    *将某个key提升为最近使用的元素
    */
    void makeRecently(int key){
        Node* x=map.at(key);
        cache->remove(x);
        cache->addLast(x);
    }
    /*
    *添加最近使用的元素
    */
    void addRecently(int key,int val){
        Node* x=new Node(key,val);
        cache->addLast(x);
        map[key]=x;
    }
    /*
    *删除某个key
    */
    void deleteKey(int key){
        Node * x=map.at(key);
        cache->remove(x);
        map.erase(key);
        delete x;
    }
    /*
    *删除最久未使用的元素
    */
    void removeLeastRecently(){
        Node* deleteNode=cache->removeFirst();
        int deleteKey=deleteNode->key;
        map.erase(deleteKey);
        delete deleteNode;
    }
public:
    LRUCache(int capacity) {
        this->capacity=capacity;
        cache=new DoubleList();
    }
    
    int get(int key) {
        if(map.find(key)==map.end()){
            return -1;
        }
        makeRecently(key);
        return map.at(key)->val;
    }
    
    void put(int key, int value) {
        if(map.find(key)!=map.end()){
            deleteKey(key);
            addRecently(key,value);
            return;
        }
        if(capacity==cache->size()){
            removeLeastRecently();
        }
        addRecently(key,value);
    } 
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值