LruCache实现

news2025/1/31 13:03:31

LRU最近最少使用算法

一、LRU算法

1.简介

LRU(Least Recently Used,最近最少使用)算法是一种常用的缓存淘汰策略,当缓存达到其容量上限时,它会移除那些最久没有被访问的数据项。这种策略基于这样一个假设:如果一个数据项在近期没有被访问过,那么在未来一段时间内也不太可能被访问。

2.LRU算法的核心思想

LRU算法的核心在于追踪每个数据项的访问历史,并优先保留最近被访问过的数据项。具体来说,每当有新的数据需要存储而缓存已满时,LRU算法会选择移除那个最长时间未被访问的数据项。

二、算法题目

1.LeetCode题目

146. LRU 缓存

2.实现


class LRUCache extends LinkedHashMap<Integer, Integer> {

        private int capacity;

        public LRUCache(int capacity) {
            super(capacity, 0.75F, true);
            this.capacity = capacity;
        }

        public int get(int key) {
            return getOrDefault(key, -1);
        }

        public void put(int key, int value) {
            super.put(key, value);
        }

        @Override
        protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
            return size() > capacity;
        }
    }

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

三、项目中实现

  • 定义Cache接口
package com.zzc.design.cache;

import java.util.concurrent.Callable;

public interface Cache<K, V> {

    /**
     * 添加值到缓存中,如果key已经存在,值将会被覆盖
     * @param key
     * @param val
     */
    void put(K key, V val);

    /**
     * 根据key从缓存中获取value
     * @param key
     * @return
     */
    V get(K key);

    /**
     * “加载-通过”模式(load-through pattern)
     * 从缓存中获取值,如果该值不存在,则通过给定的函数处理并将其结果更新到缓存中。
     * @param key
     * @param call
     * @return
     * @throws Exception
     */
    V get(K key, Callable<? extends V> call) throws Exception;

    /**
     * 通过key移除缓存
     * @param key
     * @return
     */
    V remove(K key);

    /**
     * 清除整个缓存
     */
    void clear();

    /**
     * 缓存数量大小
     * @return
     */
    int getCapacity();

}

  • 实现具体存储key-value数据的接口
package com.zzc.design.cache;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

public class SimpleCache<K, V> implements Cache<K, V> {

    private final Map<K, V> cache;

    public SimpleCache(int size) {
        cache = new HashMap<>(size);
    }

    @Override
    public void put(K key, V val) {
        cache.put(key, val);
    }

    @Override
    public V get(K key) {
        return cache.get(key);
    }

    @Override
    public V get(K key, Callable<? extends V> call) throws Exception {
        if (cache.containsKey(key)) {
            return cache.get(key);
        } else {
            V v2 = call.call();
            cache.put(key, v2);
            return v2;
        }
    }

    @Override
    public V remove(K key) {
        return cache.remove(key);
    }

    @Override
    public void clear() {
        cache.clear();
    }

    @Override
    public int getCapacity() {
        return cache.size();
    }

}

  • 拓展LRU缓存类型
package com.zzc.design.cache.lru;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;

public class LruCache<K, V> implements Cache<K, V> {

    /**
     * 存储键值对数据
     */
    private final Cache<K, V> delegate;

    /**
     * 跟踪键的访问顺序,从而实现 LRU 策略
     */
    private Map<K, V> visits;

    /**
     * 记录最近要被移除的最老键
     */
    private K eldestKey;

    public LruCache(Cache<K, V> delegate, int capacity) {
        this.delegate = delegate;
        setCapacity(capacity);
    }

    public void setCapacity(final int capacity) {
        visits = new LinkedHashMap<K, V>(capacity, .75F, true) {

            @Override
            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
                boolean tooBig = size() > capacity;
                if (tooBig) {
                    eldestKey = eldest.getKey();
                }
                return tooBig;
            }
        };
    }

    @Override
    public void put(K key, V val) {
        delegate.put(key, val);
        cycleKeyList(key);
    }

    @Override
    public V get(K key) {
        visits.get(key);
        return delegate.get(key);
    }

    @Override
    public V get(K key, Callable<? extends V> call) throws Exception {
        return delegate.get(key, call);
    }

    @Override
    public V remove(K key) {
        return delegate.remove(key);
    }

    @Override
    public void clear() {
        delegate.clear();
        visits.clear();
    }

    @Override
    public int getCapacity() {
        return delegate.getCapacity();
    }

    private void cycleKeyList(K key) {
        visits.put(key, null);
        if (eldestKey != null) {
            delegate.remove(eldestKey);
            eldestKey = null;
        }
    }
}

  • Demo示例
package com.zzc.design.cache.lru;

import com.zzc.design.cache.Cache;
import com.zzc.design.cache.SimpleCache;

public class Demo {

    private static final int initCapacity = 1;
    private static final int maxCapacity = 3;

    public static void main(String[] args) {
        Cache<String, String> cache = new LruCache<>(new SimpleCache<>(initCapacity), maxCapacity);
        cache.put("key1", "value1");
        cache.put("key2", "value2");
        cache.put("key3", "value3");
        System.out.println(cache.get("key1"));//访问key1
        System.out.println(cache.get("key2"));//访问key2
        System.out.println(cache.get("key3"));//访问key3
        System.out.println(cache.get("key1"));//访问key1
        System.out.println(cache.get("key2"));//访问key2
        cache.put("key4", "value4");//新增key4
        System.out.println(cache.get("key3"));//key3的访问次数最少,在添加key4的时候被删除掉了
    }

}
/*
 * 结果:
 * value1
 * value2
 * value3
 * value1
 * value2
 * null
 */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2286928.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MySQL】MySQL客户端连接用 localhost和127.0.0.1的区别

# systemctl status mysqld # ss -tan | grep 3306 # mysql -V localhost与127.0.0.1的区别是什么&#xff1f; 相信有人会说是本地IP&#xff0c;曾有人说&#xff0c;用127.0.0.1比localhost好&#xff0c;可以减少一次解析。 看来这个入门问题还有人不清楚&#xff0c;其实…

MySQL(高级特性篇) 14 章——MySQL事务日志

事务有4种特性&#xff1a;原子性、一致性、隔离性和持久性 事务的隔离性由锁机制实现事务的原子性、一致性和持久性由事务的redo日志和undo日志来保证&#xff08;1&#xff09;REDO LOG称为重做日志&#xff0c;用来保证事务的持久性&#xff08;2&#xff09;UNDO LOG称为回…

【Block总结】HWD,小波下采样,适用分类、分割、目标检测等任务|即插即用

论文信息 Haar wavelet downsampling (HWD) 是一项针对语义分割的创新模块&#xff0c;旨在通过减少特征图的空间分辨率来提高深度卷积神经网络&#xff08;DCNNs&#xff09;的性能。该论文的主要贡献在于提出了一种新的下采样方法&#xff0c;能够在下采样阶段有效地减少信息…

【解决方案】MuMu模拟器移植系统进度条卡住98%无法打开

之前在Vmware虚拟机里配置了mumu模拟器&#xff0c;现在想要移植到宿主机中 1、虚拟机中的MuMu模拟器12-1是目标系统&#xff0c;对应的目录如下 C:\Program Files\Netease\MuMu Player 12\vms\MuMuPlayer-12.0-1 2、Vmware-虚拟机-设置-选项&#xff0c;启用共享文件夹 3、复…

力扣面试150 快乐数 循环链表找环 链表抽象 哈希

Problem: 202. 快乐数 &#x1f469;‍&#x1f3eb; 参考题解 Code public class Solution {public int squareSum(int n) {int sum 0;while(n > 0){int digit n % 10;sum digit * digit;n / 10;}return sum;}public boolean isHappy(int n) {int slow n, fast squa…

安卓(android)实现注册界面【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的&#xff08;如果代码有错漏&#xff0c;可查看源码&#xff09; 1.掌握LinearLayout、RelativeLayout、FrameLayout等布局的综合使用。 2.掌握ImageView、TextView、EditText、CheckBox、Button、RadioGroup、RadioButton、ListView、RecyclerView等控件在项目中的…

SpringSecurity:There is no PasswordEncoder mapped for the id “null“

文章目录 一、情景说明二、分析三、解决 一、情景说明 在整合SpringSecurity功能的时候 我先是去实现认证功能 也就是&#xff0c;去数据库比对用户名和密码 相关的类&#xff1a; UserDetailsServiceImpl implements UserDetailsService 用于SpringSecurity查询数据库 Logi…

微服务入门(go)

微服务入门&#xff08;go&#xff09; 和单体服务对比&#xff1a;里面的服务仅仅用于某个特定的业务 一、领域驱动设计&#xff08;DDD&#xff09; 基本概念 领域和子域 领域&#xff1a;有范围的界限&#xff08;边界&#xff09; 子域&#xff1a;划分的小范围 核心域…

996引擎 - NPC-动态创建NPC

996引擎 - NPC-动态创建NPC 创建脚本服务端脚本客户端脚本添加自定义音效添加音效文件修改配置参考资料有个小问题,创建NPC时没有控制朝向的参数。所以。。。自己考虑怎么找补吧。 多重影分身 创建脚本 服务端脚本 Mir200\Envir\Market_Def\test\test001-3.lua -- NPC八门名…

基于MinIO的对象存储增删改查

MinIO是一个高性能的分布式对象存储服务。Python的minio库可操作MinIO&#xff0c;包括创建/列出存储桶、上传/下载/删除文件及列出文件。 查看帮助信息 minio.exe --help minio.exe server --help …

观察者模式和订阅发布模式的关系

有人把观察者模式等同于发布订阅模式&#xff0c;也有人认为这两种模式存在差异&#xff0c;本质上就是调度的方法不同。 发布订阅模式: 观察者模式: 相比较&#xff0c;发布订阅将发布者和观察者之间解耦。&#xff08;发布订阅有调度中心处理&#xff09;

(2025 年最新)MacOS Redis Desktop Manager中文版下载,附详细图文

MacOS Redis Desktop Manager中文版下载 大家好&#xff0c;今天给大家带来一款非常实用的 Redis 可视化工具——Redis Desktop Manager&#xff08;简称 RDM&#xff09;。相信很多开发者都用过 Redis 数据库&#xff0c;但如果你想要更高效、更方便地管理 Redis 数据&#x…

Baklib引领内容管理平台新时代优化创作流程与团队协作

内容概要 在迅速变化的数字化时代&#xff0c;内容管理平台已成为各种行业中不可或缺的工具。通过系统化的管理&#xff0c;用户能够有效地组织、存储和共享信息&#xff0c;从而提升工作效率和创意表达。Baklib作为一款新兴的内容管理平台&#xff0c;以其独特的优势和创新功…

Java实现.env文件读取敏感数据

文章目录 1.common-env-starter模块1.目录结构2.DotenvEnvironmentPostProcessor.java 在${xxx}解析之前执行&#xff0c;提前读取配置3.EnvProperties.java 这里的path只是为了代码提示4.EnvAutoConfiguration.java Env模块自动配置类5.spring.factories 自动配置和注册Enviro…

房屋租赁系统在数字化时代中如何重塑租赁服务与提升市场竞争力

内容概要 在当今快速发展的数字化时代&#xff0c;房屋租赁系统的作用愈发重要。随着市场需求的变化&#xff0c;租赁服务正面临着新的挑战与机遇。房屋租赁系统不仅仅是一个简单的管理工具&#xff0c;更是一个能够提升用户体验和市场竞争力的重要平台。其核心功能包括合同管…

C++ ——— 学习并使用 priority_queue 类

目录 何为 priority_queue 类 学习并使用 priority_queue 类 实例化一个 priority_queue 类对象 插入数据 遍历堆&#xff08;默认是大堆&#xff09; 通过改变实例化的模板参数修改为小堆 何为 priority_queue 类 priority_queue 类为 优先级队列&#xff0c;其本质就是…

DeepSeek 模型全览:探索不同类别的模型

DeepSeek 是近年来备受关注的 AI 研究团队&#xff0c;推出了一系列先进的深度学习模型&#xff0c;涵盖了大语言模型&#xff08;LLM&#xff09;、代码生成模型、多模态模型等多个领域。本文将大概介绍 DeepSeek 旗下的不同类别的模型&#xff0c;帮助你更好地理解它们的特点…

Three.js实现3D动态心形与粒子背景的数学与代码映射解析

一、效果概述 本文通过Three.js构建了一个具有科技感的3D场景&#xff0c;主要包含两大视觉元素&#xff1a; 动态心形模型&#xff1a;采用数学函数生成基础形状&#xff0c;通过顶点操作实现表面弧度。星空粒子背景&#xff1a;随机分布的粒子群组形成空间层次感。复合动画…

linux asio网络编程理论及实现

最近在B站看了恋恋风辰大佬的asio网络编程&#xff0c;质量非常高。在本章中将对ASIO异步网络编程的整体及一些实现细节进行完整的梳理&#xff0c;用于复习与分享。大佬的博客&#xff1a;恋恋风辰官方博客 Preactor/Reactor模式 在网络编程中&#xff0c;通常根据事件处理的触…

多目标优化策略之一:非支配排序

多目标优化策略中的非支配排序是一种关键的技术,它主要用于解决多目标优化问题中解的选择和排序问题,确定解集中的非支配解(也称为Pareto解)。 关于什么是多目标优化问题,可以查看我的文章:改进候鸟优化算法之五:基于多目标优化的候鸟优化算法(MBO-MO)-CSDN博客 多目…