Java算法_ LRU 缓存(LeetCode_Hot100)

题目描述:请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
获得更多?算法思路:代码文档,算法解析的私得。
运行效果

完整代码

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

/**
 * 2 * @Author: LJJ
 * 3 * @Date: 2023/8/7 13:14
 * 4
 */
public class LRUCache {
    class Node{
        int key;
        String value;
        Node prev;
        Node next;

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

    private int capacity;
    private Map<Integer,Node> cache;
    private Node head;
    private Node tail;

    // 初始化LRUCache类的构造函数,
    // 使用了一个哨兵节点的技巧,将head和tail初始化为哨兵节点,并不存储具体的键值对。
    // 哨兵节点可以简化链表的操作,避免处理头部和尾部节点时需要特殊处理的情况。
    public LRUCache(int capacity){
        this.capacity = capacity;
        cache = new HashMap<>();
        //初始化头尾节点;
        head = new Node(-1, "-1");
        tail = new Node(-1, "-1");
        head.next = tail;
        tail.prev = head;
    }

    public String get(int key){
       if (cache.containsKey(key)){
            Node node = cache.get(key);
            //将查到的节点移动到链表头部
            removeNode(node);
            addToHead(node);
            return node.value;
        }
        return "-1";
    }

    public void put(int key, String value){
        if (cache.containsKey(key)){
            Node node = cache.get(key);
            node.value = value;
            //将更新后的节点移动到链表头部
            removeNode(node);
            addToHead(node);
        }else {
            if (cache.size() >= capacity){

                //如果缓存已满,需要移除最久未使用的节点(即链表尾部节点)
                cache.remove(tail.prev.key);
                removeNode(tail.prev);
            }
            Node newNode = new Node(key,value);
            cache.put(key,newNode);
            //将新的节点插入链表头部
            addToHead(newNode);
        }
    }

    // 将节点插入链表头部
    private void addToHead(Node node){
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
        node.prev = head;
    }

    //移除节点
    private void removeNode(Node node){
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private static void printCache(Node head){
        Node current = head;
        while (current != null){
            System.out.print("(" + current.key + ", " + current.value + ") -> ");
            current = current.next;
        }
        System.out.println("null");
    }
    public static void main(String[] args) {
        LRUCache lruCache = new LRUCache(3);

        // 插入键值对 (1, "A")
        lruCache.put(1, "A");
        // 插入键值对 (2, "B")
        lruCache.put(2, "B");
        // 插入键值对 (3, "C")
        lruCache.put(3, "C");

        // 此时缓存状态为:3 -> 2 -> 1,其中1是最近访问的,3是最久未使用的
        System.out.println("初始缓存状态为:");
        printCache(lruCache.head);
        // 获取键1对应的值,输出"A"
        System.out.println(" // 获取键1对应的值:"+lruCache.get(1));

        // 此时缓存状态不变:1 -> 3 -> 2
        System.out.println("获取键1对应的值,输出\"A\"后的缓存状态为:");
        printCache(lruCache.head);
        // 插入键值对 (4, "D"),此时缓存已满,需要逐出最久未使用的键值对,即键2 -> 值B被逐出
        lruCache.put(4, "D");

        // 此时缓存状态为:4 -> 1 -> 3,其中3是最久未使用的,4是最近访问的
        System.out.println("插入键值对 (4, \"D\"),此时缓存已满,需要逐出最久未使用的键值对,即键2 -> 值B被逐出的缓存状态为:");
        printCache(lruCache.head);
        // 获取键2对应的值,由于键2已经被逐出,输出-1
        System.out.println("获取键2对应的值:"+lruCache.get(2));

        // 此时缓存状态不变:4 -> 1 -> 3
        System.out.println("获取键2对应的值,由于键2已经被逐出,输出-1的缓存状态为:");
        printCache(lruCache.head);
        // 插入键值对 (5, "E"),此时缓存已满,需要逐出最久未使用的键值对,即键3 -> 值C被逐出
        lruCache.put(5, "E");

        // 此时缓存状态为:5 -> 4 -> 1,其中1是最久未使用的,5是最近访问的
        System.out.println("插入键值对 (5, \"E\"),此时缓存已满,需要逐出最久未使用的键值对,即键3 -> 值C被逐出的缓存状态为:");
        printCache(lruCache.head);
        // 获取键3对应的值,由于键3已经被逐出,输出-1
        System.out.println("获取键3对应的值:"+lruCache.get(3));

        // 此时缓存状态不变:5 -> 4 -> 1
        System.out.println(" // 获取键3对应的值,由于键3已经被逐出,输出-1的缓存状态为:");
        printCache(lruCache.head);
    }
}
相关推荐
CoderYanger3 分钟前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc
学电子她就能回来吗5 分钟前
LeetCode Hot 100|普通数组专题学习笔记(零基础版)
笔记·算法·leetcode
用户老李7 分钟前
反向传播计算梯度举例
算法
niyongsheng8 分钟前
多智能体连续时间内路径规划:AA-SIPP(m) 的 Rust 实现与算法
算法·rust·机器人
顽疲24 分钟前
java springboot vue 养老系统源码详解:请假 care_leave 销假与床位停费日扣实践
java·vue.js·spring boot
XIAEE1 小时前
一个即时通讯项目是怎么长出来的:(Spring Boot 3 + Vue 3 微前端 + 悟空 IM + LiveKit)
java·spring
n87651 小时前
Playwright Java WEB UI 自动化实现框架与逻辑
java·前端·ui
Java_AI工程师1 小时前
Spring4 / SpringBoot1.x 老项目想接入 AI?不用升级框架!3 套无痛落地方案
java·人工智能·spring boot
BBmmo1 小时前
Java Stream 的 filter 为什么看起来没运行?
java
302wanger1 小时前
DeepSeek-V4.1-Flash-1017 免费用到1024,速来
算法