手写LRU 缓存

主要逻辑:

要有一个hashMap存储节点,实现o(1)的查找

要有一个双向链表,实现实现最近或刚添加的节点在头节点,

初始容量,每添加一个节点,就记录当前已添加的个数,如果添加之后已超过容量,则移除尾部的节点和hashMap里面的节点

java 复制代码
public class LRUCacheDemo {
    class LRUNode {
        private int key;
        private int value;
        private LRUNode prev;
        private LRUNode next;

        public LRUNode() {
        }

        public LRUNode(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    private Map<Integer, LRUNode> cache = new HashMap<>();
    private int capacity;
    private int size;
    private LRUNode head, tail;

    public LRUCacheDemo(int capacity) {
        this.capacity = capacity;
        this.size = 0;
        head = new LRUNode();
        tail = new LRUNode();
        head.next = tail;
        tail.prev = head;
    }
    public int get(int key) {
        LRUNode lruNode = cache.get(key);
        if (lruNode == null) {
            return -1;
        }
        moveNodeToHead(lruNode);
        return lruNode.value;
    }
    public void put(int key, int value) {
        // 从缓存中查询,如果存在,则更新value, 并把对应的node移到头部
        LRUNode lruNode = cache.get(key);
        if (lruNode != null) {
            lruNode.value = value;
            moveNodeToHead(lruNode);
        } else {

            // 如果不存在,则直接插入

            // 放入hashMap
            LRUNode node = new LRUNode(key, value);
            cache.put(key, node);

            // 添加到双向链表的头部
            addToHead(node);
            size++;
            // 然后看容量是否超过了,如果超过了,则移除双向链表尾部的节点,并移除cache的节点
            if (size > capacity) {
                LRUNode tail = removeTail();
                cache.remove(tail.key);
                size--;

            }
        }


    }

    private LRUNode removeTail() {
        LRUNode tail = this.tail.prev;
        removeNode(tail);
        return tail;
    }

    private void moveNodeToHead(LRUNode lruNode) {
        removeNode(lruNode);
        addToHead(lruNode);
    }

    private void addToHead(LRUNode lruNode) {
        lruNode.prev = head;
        lruNode.next = head.next;
        head.next.prev = lruNode;
        head.next = lruNode;

    }

    private void removeNode(LRUNode lruNode) {
        lruNode.prev.next = lruNode.next;
        lruNode.next.prev =lruNode.prev;
    }

    public static void main(String[] args) {
        LRUCacheDemo lruCacheDemo = new LRUCacheDemo(2);
        lruCacheDemo.put(1,1);
        lruCacheDemo.put(2,2);
        lruCacheDemo.get(2);
        lruCacheDemo.put(3, 3);
        lruCacheDemo.put(4, 4);
        lruCacheDemo.get(1);
    }
}
相关推荐
Seven9718 小时前
虚拟线程深度解析:轻量并发编程的未来趋势
java
雨中飘荡的记忆1 天前
ElasticJob分布式调度从入门到实战
java·后端
考虑考虑2 天前
JDK25模块导入声明
java·后端·java ee
_小马快跑_2 天前
Java 的 8 大基本数据类型:为何是不可或缺的设计?
java
Re_zero2 天前
线上日志被清空?这段仅10行的 IO 代码里竟然藏着3个毒瘤
java·后端
洋洋技术笔记2 天前
Spring Boot条件注解详解
java·spring boot
程序员清风2 天前
程序员兼职必看:靠谱软件外包平台挑选指南与避坑清单!
java·后端·面试
皮皮林5512 天前
利用闲置 Mac 从零部署 OpenClaw 教程 !
java
NE_STOP3 天前
springMVC-HTTP消息转换器与文件上传、下载、异常处理
spring
华仔啊3 天前
挖到了 1 个 Java 小特性:var,用完就回不去了
java·后端