LeetCode第 146 题:LRU缓存机制(C++)

146. LRU缓存机制 - 力扣(LeetCode)
在这里插入图片描述

LRU需要注意:

  • 1、访问了某个元素之后,就要把这个元素的位置放到缓存的头部(最近使用)
  • 2、向缓存写入数据是,先检查该数据是否存在,如果不存在,则在头部写入,否则就将存在的值移动到头部(因为也算是进行了访问),题目还要求了对存在的值进行修改
  • 3、缓存满了之后,从缓存的尾部(最久没使用)开始删除元素以腾出空间

第一条,需要移除该元素,并将该元素放到头部,也就是快速的删除和添加,删除的元素可能在任何位置。那就最好使用链表了,链表删除/添加元素的复杂度为O(1)。但是,题目要求是先访问这个元素,链表的快速删除/添加是建立在给出待删除位置的迭代器的前提下的,那怎么找到这个元素呢?链表不能随机访问,所以只能遍历链表,复杂度为O(n),所以第一个操作复杂度就是O(n),主要是定位到相应的key值需要遍历。

第二条,写入数组同样需要知道该key是否存在,总不能又遍历一次吧?其实题目给出的pair<key, value>已经暗示了使用map了。map可以实现O(1)的查找,就可以知道该元素是否已经存在,如果用map指向链表:<key = key, value = 指向链表中key为当前key的元素的指针(迭代器)>,而链表中的元素也是一个pair<key, value>。我们在构造链表的时候随时维护一个相应的map,就可以实现O(1)复杂度的查找以及元素定位。

第三条,删除元素的时候维护的map也要实时更新。

class LRUCache {
public:
    LRUCache(int capacity) : cap(capacity) {}
    
    int get(int key) {
        if(m.count(key) != 0){
            int val = m[key]->second;
            l.erase(m[key]);
            l.push_front({key, val});//访问过的元素移动到头部
            m[key] = l.begin();
            return val;
        }
        return -1;
    }
    
    void put(int key, int value) {
        if(m.count(key) != 0){//已经存在
            l.erase(m[key]);
            l.push_front({key, value});
            m[key] = l.begin();
        }else{
            if(l.size() == cap){//同步删除
                m.erase(l.back().first);
                l.pop_back();
            }
            l.push_front({key, value});
            m[key] = l.begin();
        }
    }
private:
    int cap;
    list<pair<int, int>>    l;
    unordered_map<int, list<pair<int, int>>::iterator>  m;
};

进阶,上述的lru不是线程安全的(get和put操作都不是),如果要想线程安全的话,需要加锁:

get和put函数的第一行:

std::lock_guard<std::mutex> lck(cache_mutex_);

private处:

std::mutex cache_mutex_;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值