LRU缓存算法设计

LRU 缓存算法的核⼼数据结构就是哈希链表双向链表哈希表 的结合体。这个数据结构⻓这样:

创建的需要有两个方法,一个是get方法,一个是put方法。

一些问题:为什么需要使用双向链表呢?因为删除链表的本身,需要得到他的前一个节点。如果使用单链表,效率就会很低,这边是使用的空间换取效率。

java 复制代码
//Node 节点类
public class Node {
    public  int key,val;
    public Node pre,next;
    public Node(int key,int val){
        this.key=key;
        this.val=val;
    }

}
java 复制代码
public class DoubleList {
    //头和尾
    public   Node head,tail;
    public int size;
    public DoubleList(){
        //两个哨兵
        head=new Node(0,0);
        tail=new Node(0,0);
        head.next=tail;
        tail.pre=head;
        size=0;
    }
    public  void addLast(Node x){
        //添加到末尾去
        //在tail之前插入一个 
        x.pre=tail.pre; //
        x.next=tail;
        tail.pre.next=x;
        tail.pre=x;
        size++;
    }
    public void remove(Node x) {
        //双链表删除一个节点  x.pre.next=x.next;
        x.pre.next = x.next;
        x.next.pre = x.pre;
        size--;
    }
    // 删除链表中第⼀个节点,并返回该节点,时间 O(1)
    public Node removeFirst() {
        if (head.next == tail)
            return null;
        Node first = head.next;
        remove(first);
        return first;
    }
    public int size() { return size; }
}

缓存设计的代码:

java 复制代码
import java.util.HashMap;

public class LRUCache {
    // key -> Node(key, val)
    private HashMap<Integer, Node> map;
    // Node(k1, v1) <-> Node(k2, v2)...
    private DoubleList cache;
    // 最⼤容量
    private int cap; //最大容量

    public LRUCache(int capacity) {
        this.cap = capacity;
        map = new HashMap<>();
        cache = new DoubleList();
    }

    private void makeRecently(int key) {
        Node x = map.get(key); //变为最近的    删除 然后添加进来
        // 先从链表中删除这个节点
        cache.remove(x);
        // 重新插到队尾
        cache.addLast(x);
    }
    private void addRecently(int key, int val) {
        Node x = new Node(key, val);
        // 链表尾部就是最近使⽤的元素
        cache.addLast(x);
        // 别忘了在 map 中添加 key 的映射
        map.put(key, x);
    }
    private void deleteKey(int key) {
        Node x = map.get(key);
        // 从链表中删除
        cache.remove(x);
        // 从 map 中删除
        map.remove(key);  //mp中也要删除
    }
    private void removeLeastRecently() {  //删除最久没有使用的
        // 链表头部的第⼀个元素就是最久未使⽤的
        Node deletedNode = cache.removeFirst();
        // 同时别忘了从 map 中删除它的 key
        int deletedKey = deletedNode.key;
        map.remove(deletedKey);
    }
    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        // 将该数据提升为最近使⽤的
        makeRecently(key); //修改
        return map.get(key).val;
    }
    public void put(int key, int val) {
        //如果之前含有  删除 并添加
        if (map.containsKey(key)) {
            // 删除旧的数据
            deleteKey(key);
            // 新插⼊的数据为最近使⽤的数据
            addRecently(key, val);
            return;
        }
   //如果慢了 那么删除
        if (cap == cache.size()) {
            // 删除最久未使⽤的元素
            removeLeastRecently();
        }
        // 添加为最近使⽤的元素
        addRecently(key, val);
    }
}

一些算法的设计思路:,变为最近的。首先得到这个点,然后删除这个点。

添加到最近来 就需要new出来这个节点,然后加入到最后去。

删除 首先先得到,再从链表中删除掉。不要忘记hashmap中也是需要删除的。

如果满了,需要删除掉最早的那个节点。

test测试结果

通过测试发现 2已经被移除去了。

相关推荐
dhxhsgrx1 小时前
PYTHON训练营DAY25
java·开发语言·python
Musennn1 小时前
leetcode 15.三数之和 思路分析
算法·leetcode·职场和发展
不知几秋2 小时前
数字取证-内存取证(volatility)
java·linux·前端
CM莫问3 小时前
<论文>(微软)避免推荐域外物品:基于LLM的受限生成式推荐
人工智能·算法·大模型·推荐算法·受限生成
康谋自动驾驶4 小时前
康谋分享 | 自动驾驶仿真进入“标准时代”:aiSim全面对接ASAM OpenX
人工智能·科技·算法·机器学习·自动驾驶·汽车
chxii5 小时前
5java集合框架
java·开发语言
?abc!5 小时前
缓存(3):本地缓存作用 及 数据一致性 实现策略
缓存
C++ 老炮儿的技术栈5 小时前
什么是函数重载?为什么 C 不支持函数重载,而 C++能支持函数重载?
c语言·开发语言·c++·qt·算法
yychen_java6 小时前
R-tree详解
java·算法·r-tree
JANYI20186 小时前
嵌入式设计模式基础--C语言的继承封装与多态
java·c语言·设计模式