Java23-实现LRU缓存

157 阅读2分钟

1、思考

  • 需要一个最大的缓存量
  • put进去值得时候,是有顺序的,每次放在最前面
  • get的时候查询很快,查完后放在最前,代表着优先级
  • 当满的时候,删除在队尾的元素

2、需要有顺序,且查询快,则选择数据结构为LinkedHashMap(继承与HashMap),是双向链表和哈希表的结合体 结构如下图所示:

1.jpg

  • 每次默认从链表尾部添加元素,越靠近尾部的就是最近使用的,越靠头部的元素就是最近未使用的
  • 对于某一个key,我们可以通过哈希表快速定位到链表中的节点,从而取得对应的值
  • 传统的来链表支持快速增删,但是无法按照索引访问每一个位置的元素,借助哈希表 为什么要是双向链表,单链表行不行?另外,既然哈希表中已经存了 key,为什么链表中还要存 key 和 val 呢,只存 val 不就行了
    删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持直接查找前驱,保证操作的时间复杂度 O(1)。

代码

class LRUCache {
    int cap;
    LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
    //进行初始化
    public LRUCache(int capacity) {
        this.cap = capacity;
    }

    //获得逻辑 若他是之前已经得到的,把之前的key,变为最近使用
    //若不包含,返回-1
    public int get(int key) {
        if (!cache.containsKey(key)) {
            return -1;
        }
        // 将 key 变为最近使用
        makeRecently(key);
        return cache.get(key);
    }

    //新加入,包含则修改key值,将key变为最近使用的
    //否则。则判断是否缓存已经满了,满了,则删除链表头部的元素,进行删除
    //调用迭代器,一直迭代到最前面
    //没满,则直接加入
    public void put(int key, int val) {
        if (cache.containsKey(key)) {
            // 修改 key 的值
            cache.put(key, val);
            // 将 key 变为最近使用
            makeRecently(key);
            return;
        }

        if (cache.size() >= this.cap) {
            // 链表头部就是最久未使用的 key
            int oldestKey = cache.keySet().iterator().next();
            cache.remove(oldestKey);
        }
        // 将新的 key 添加链表尾部
        cache.put(key, val);
    }

    //最近使用:得到之前的,将之前的进行删除,再重新加到队尾中
    private void makeRecently(int key) {
        int val = cache.get(key);
        // 删除 key,重新插入到队尾
        cache.remove(key);
        //将新的对应的值进行插入
        cache.put(key, val);
    }
}

总结:

  • 什么情况下才会提高优先级? 刚访问过,具有重复的,新添加的
  • 提高优先级的方法定义
  • 缓存使用linkedHashMap来实现

优先级方法的定义

//优先级的提高不包活缓存中没有的,在map尾部就是优先级最高的
public void makeRecently(int key){
    int value = cache.get(key);
    cache.remove(key);
    cache.put(key,value);
}

刚访问一个元素更新优先级

public int get(int key){
    if(!cache.containsKey(key)){
        return -1;
    }
    makeRecently(key);
    return cache.get(key);
}

添加元素

public void put(int key,int value){
    if(cache.containsKey(key)){
        makeRencently(key);    //只能提升优先级
        cache.put(key,value);  //他还是要进行put的
        return;
    }
    //动 > 静
    if(cache.size()>=cap){
        //找出最前面的那个
        int first = cache.keySet().iterator().next();
        cache.remove(first);
    }
   cache.put(key,value);
}