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);
    }
}
相关推荐
GalaxyPokemon23 分钟前
LeetCode - 53. 最大子数组和
算法·leetcode·职场和发展
stein_java38 分钟前
springMVC-10验证及国际化
java·spring
weixin_4786897641 分钟前
C++ 对 C 的兼容性
java·c语言·c++
hn小菜鸡1 小时前
LeetCode 1356.根据数字二进制下1的数目排序
数据结构·算法·leetcode
zhuiQiuMX1 小时前
分享今天做的力扣SQL题
sql·算法·leetcode
LUCIAZZZ1 小时前
HikariCP数据库连接池原理解析
java·jvm·数据库·spring·springboot·线程池·连接池
sky_ph2 小时前
JAVA-GC浅析(二)G1(Garbage First)回收器
java·后端
IDRSolutions_CN2 小时前
PDF 转 HTML5 —— HTML5 填充图形不支持 Even-Odd 奇偶规则?(第二部分)
java·经验分享·pdf·软件工程·团队开发
hello早上好2 小时前
Spring不同类型的ApplicationContext的创建方式
java·后端·架构
music&movie2 小时前
算法工程师认知水平要求总结
人工智能·算法