手写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);
    }
}
相关推荐
jinanwuhuaguo30 分钟前
(第三十三篇)五月的文明奠基:OpenClaw 2026.5.2版本的文明级解读
android·java·开发语言·人工智能·github·拓扑学·openclaw
倒霉蛋小马34 分钟前
【Redis】什么是缓存穿透?
缓存
xmjd msup1 小时前
spring security 超详细使用教程(接入springboot、前后端分离)
java·spring boot·spring
952361 小时前
SpringBoot统一功能处理
java·spring boot·后端
Lyyaoo.2 小时前
优惠券秒杀业务分析
java·开发语言
消失的旧时光-19432 小时前
统一并发模型:线程、Reactor、协程本质是一件事(从线程到协程 · 第6篇·终章)
java·python·算法
勿忘初心12212 小时前
Java 国密 SM4 加密工具类实战(Hutool + BouncyCastle)|企业级数据加密 + 兼容 JDK8
java·数据安全·数据加密·后端开发·企业级开发·国密 sm4
庞轩px2 小时前
第8篇:原子类与CAS底层原理——无锁并发的实现
java·cas·乐观锁·aba·无锁编程·自旋
rleS IONS2 小时前
SpringBoot中自定义Starter
java·spring boot·后端
苍煜2 小时前
慢SQL优化实战教学
java·数据库·sql