LRU算法

1. 算法介绍

LRU(Least Recently Used)算法是一种常见的缓存替换算法,用于管理缓存中的数据项。它的核心思想是将最近最少使用的数据项(最久未被访问的数据项)替换出缓存,以便为新的数据项腾出空间。

LRU算法通常基于以下原则工作:

  1. 维护访问顺序: LRU算法维护一个数据项的访问顺序。当某个数据项被访问时,它会被移动到队列的最前面(或者叫做"最近使用"的位置)。

  2. 替换最远的数据项: 当需要替换缓存中的数据项时,LRU算法会选择队列中位于末尾的数据项,因为它们是最近最少使用的。

  3. 常用数据项保持在缓存中: LRU算法的目标是确保经常访问的数据项保持在缓存中,以提高缓存的命中率,减少对底层存储的访问。

在这里插入图片描述

LRU算法的实现方式可以有多种,包括使用双向链表、哈希表或其他数据结构。以下是一个基本的LRU算法实现步骤:

  1. 使用双向链表(或其他适当的数据结构)来维护数据项的访问顺序,其中链表头表示最近使用的数据项,链表尾表示最久未使用的数据项。
  2. 当某个数据项被访问,将其移动到链表头。
  3. 当需要替换数据项时,选择链表尾的数据项进行替换,并从链表中移除。
  4. 为了更快地查找数据项,可以使用哈希表将数据项的键映射到链表节点的位置。

LRU算法在缓存管理和数据库系统中经常被使用,它有助于确保常用的数据可以快速访问,提高系统性能。然而,实际的LRU实现可能会因系统需求和性能考虑而有所不同。

2. 使用Java实现(使用LinkedHashMap)

以下是一个简单的Java实现LRU(Least Recently Used)缓存算法的示例。LRU缓存算法用于保持最近使用的数据项,并在容量不足时替换最久未使用的数据项。
在这个示例中,我们继承了LinkedHashMap,并设置了accessOrder为true,以便按访问顺序排序。在removeEldestEntry方法中,我们控制了是否需要删除最旧的元素,当缓存大小超过容量时,会删除最旧的元素。

这个示例演示了如何创建一个LRU缓存,向其添加元素,访问元素以更新其访问时间,并在需要时删除最旧的元素,以保持缓存容量。请注意,Java标准库中的LinkedHashMap可以方便地实现LRU缓存算法。

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private final int capacity;

    public LRUCache(int capacity) {
        // 设置accessOrder为true,以便按访问顺序排序
        super(capacity, 0.75f, true);
        this.capacity = capacity;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        // 在添加新元素时,控制是否需要删除最旧的元素
        return size() > capacity;
    }

    public static void main(String[] args) {
        // 创建一个容量为3的LRU缓存
        LRUCache<String, Integer> lruCache = new LRUCache<>(3);

        lruCache.put("one", 1);
        lruCache.put("two", 2);
        lruCache.put("three", 3);

        System.out.println("Current cache content: " + lruCache);

        lruCache.get("one");  // 访问"one",使其成为最近使用的

        lruCache.put("four", 4);  // 添加新元素,触发删除最旧的元素

        System.out.println("Updated cache content: " + lruCache);
    }
}

3. 使用Java实现(手写)

/**
 * @author 曹见朋
 * @create 2023-10-27-9:15
 */
public class LRUCacheDemo {

    // 1.构造一个Node结点
    class Node<K,V>{

        K key;
        V value;
        Node<K,V> prev;
        Node<K,V> next;

        public Node() {
            this.prev=this.next=null;
        }

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
            this.prev=this.next=null;
        }

    }

    // 2. 构建一个虚拟的双向链表,里面安放的就是Node
    class DoubleLinkList<K,V>{

        Node<K,V> head;
        Node<K,V> tail;

        public DoubleLinkList() {
            head=new Node<>();
            tail=new Node<>();
            head.next=tail;
            tail.prev=head;
        }
        // 2.2 添加到头
        public void addHead(Node<K,V> node){
            node.next=head.next;
            node.prev=head;
            head.next.prev=node;
            head.next=node;
        }
        // 2.3 删除节点
        public void removeNode(Node<K,V> node){
            node.next.prev=node.prev;
            node.prev.next=node.next;
            node.next=null;
            node.prev=null;
        }
        // 2.4 获得最后一个节点
        public Node getLast(){
            return tail.prev;
        }


    }

    private int cacheSize;
    Map<Integer,Node<Integer,Integer>> map;
    DoubleLinkList<Integer,Integer> doubleLinkList;

    public LRUCacheDemo(int cacheSize) {
        this.cacheSize = cacheSize;
        map=new HashMap<>();
        doubleLinkList=new DoubleLinkList<>();
    }
    public int get(int key){ // 获取
        if(!map.containsKey(key)){ // 不存在
            return -1;
        }
        Node<Integer, Integer> integerIntegerNode = map.get(key);
        doubleLinkList.removeNode(integerIntegerNode);
        doubleLinkList.addHead(integerIntegerNode);
        return integerIntegerNode.value;
    }
    public void put(int key,int value){
        if(map.containsKey(key)){//已经存在该key
            Node<Integer, Integer> integerIntegerNode = map.get(key);
            integerIntegerNode.value=value;
            map.put(key,integerIntegerNode);
            doubleLinkList.removeNode(integerIntegerNode);
            doubleLinkList.addHead(integerIntegerNode);
        }else {
            if (map.size()==cacheSize) {//满了

                Node<Integer,Integer> lastNode=doubleLinkList.getLast();
                map.remove(lastNode.key);
                doubleLinkList.removeNode(lastNode);
            }
            //新增
            Node<Integer, Integer> objectObjectNode = new Node<>();
            map.put(key,objectObjectNode);
            doubleLinkList.addHead(objectObjectNode);
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows 离线安装 vue 环境

由于公司要求在内网开发项目&#xff0c;而内网不能连接外网&#xff0c;因此只能离线安装 vue 环境&#xff0c;在网上找过很多的离线安装方法&#xff0c;但都没有成功&#xff0c;于是在不断的尝试中找到了以下方法。 1、找一台与内网电脑相同系统的有网电脑。 2、在有网的电…

提升日期处理效率:day.js 实战经验分享

本文简介 点赞 关注 收藏 学会了 本文主要介绍我在工作中使用 day.js 较多的方法。 本文并不能代替 day.js 官方文档&#xff0c;日常工作中该查文档的还是要查文档。 本文是写给刚接触 day.js 的工友&#xff0c;让这部分工友能更顺利上手 day.js。 本文不涉及 day.js 插件…

STM32中除零运算,为何程序不崩溃?

在 C 语言中&#xff0c;除零运算会导致异常吗&#xff1f; 在 C 语言中&#xff0c;当一个数除以零时&#xff0c;会导致除法运算错误&#xff0c;通常表现为“除以零”错误或被称为“浮点异常”&#xff08;floating-point exception&#xff09;。 对于整数除法&#xff0c…

Unity的galgame形式对话系统工具

这段代码用于读取表格 using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using OfficeOpenXml; using System.IO; using UnityEngine.Networking; using UnityEngine.UI; using Random UnityEngine.Random;public class Plots…

Java中会出现内存泄漏吗

这是一个老生常谈的面试题&#xff0c;本文就系统讲解一下吧 虽然Java有GC垃圾⾃动回收功能&#xff0c;但并不是说Java程序就不会内存泄漏。如果一个对象没有地⽅会使⽤到&#xff0c;但是却仍然有引用指向他&#xff0c;那么垃圾回收器就无法回收他&#xff0c;这种情况就属于…

【哈士奇赠书活动 - 44期】- 〖从零基础到精通Flutter开发〗

文章目录 ⭐️ 赠书 - 《从零基础到精通Flutter开发》⭐️ 内容简介⭐️ 作者简介⭐️ 编辑推荐⭐️ 赠书活动 → 获奖名单 ⭐️ 赠书 - 《从零基础到精通Flutter开发》 ⭐️ 内容简介 本书由浅入深地带领读者进入Flutter开发的世界&#xff0c;从Flutter的起源讲起&#xff0c…

上海亚商投顾:沪指震荡反弹 华为汽车、卫星通信板块再度爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一、市场情绪 三大指数早盘低开低走&#xff0c;深成指、创业板指一度跌超1%&#xff0c;午后集体拉升翻红。 华为汽车概念…

MySQL之事务、存储引擎、索引

文章目录 前言一、事务1.概念2.操作&#xff08;1&#xff09;开启事务&#xff08;2&#xff09;提交事务&#xff08;3&#xff09;回滚事务 3.四大特性ACID&#xff08;1&#xff09;原子性&#xff08;Atomicity&#xff09;&#xff08;2&#xff09;一致性&#xff08;Co…

利用dns协议发起ddos反射攻击

利用DNS服务器发起反射型DDOS&#xff0c;攻击带宽 基本思路&#xff1a; 1、利用any类型的dns查询&#xff0c;可完成发送少量请求数据&#xff0c;获得大量返回数据。 2、将原请求地址改为受害者地址&#xff0c;则dns会向受害者返回大量数据&#xff0c;占用带宽 警告&…

Jenkins部署失败:JDK ‘jdk1.8.0_381‘ not supported to run Maven projects

Jenkins部署报错&#xff1a;JDK ‘jdk1.8.0_381’ not supported to run Maven projects提示使用的jdk有问题&#xff0c;启动的jdk版本不能满足项目启动。 登录Jenkins管理页面&#xff0c;系统管理——全局工具配置——JDK安装配置满足条件的JDK版本&#xff0c;保存配置&…

TSINGSEE青犀老旧小区升级改造AI+视频监控方案

一、背景与需求 近年来&#xff0c;政府高度重视城镇老旧小区改造工作&#xff0c;强调要加快老旧小区改造&#xff0c;不断完善城市管理和服务&#xff0c;彻底改变粗放型管理方式&#xff0c;让人民群众在城市生活得更方便、更舒心、更美好。老旧小区升级改造面临以下问题&a…

ETO制造商目前面临的六大挑战,如何应对?

与离散制造、库存制造不同&#xff0c;按订单设计制造&#xff08;ETO&#xff09;行业面临着一系列独特的挑战。从复杂的产品设计到与客户的密切联系&#xff0c;按订单生产的每件产品都不尽相同。 如果采用按订单生产方式制造产品&#xff0c;管理者总是会想方设法采购最好的…

cmd 命令关闭占用端口

工作中还是偶尔会遇到端口号被占用的情况&#xff0c;之前也有写过另一种关闭方式&#xff0c;但是发现没有命令方便&#xff0c;所以记录一下。 1、 查看 8081 端口占用的 pid 。 命令&#xff1a;netstat -ano |findstr 8081 由上图可知&#xff0c;占用 8081 端口的进程 id…

【ArcGIS模型构建器】05:批量为多个矢量数据添加相同的字段

本文实现借助arcgis模型构建器,实现批量为多个土地利用矢量数据添加相同的字段,例如DLMC,DLTB等。 文章目录 问题分析模型构建问题分析 有多个土地利用数据矢量图层,每个图层中有很多个图斑,现在需要给每个图层添加一个或者多个字段,如DLCM,DLBM等。 属性表如下所示: …

创建并启动华为HarmonyOS本地与远程模拟器及远程真机

1.打开设备管理器 2.选择要添加的手机设备,然后点击安装 3.正在下载华为手机模拟器 4.下载完成 5.创建新模拟器 下载系统镜像 点击下一步,创建模拟器 创建成功 启动模拟器 华为模拟器启动成功 6.登陆华为账号并使用远程模拟器 7.使用远程真机

实时数仓-Hologres介绍与架构

本文是向大家介绍Hologres是一款实时HSAP产品&#xff0c;隶属阿里自研大数据品牌MaxCompute&#xff0c;兼容 PostgreSQL 生态、支持MaxCompute数据直接查询&#xff0c;支持实时写入实时查询&#xff0c;实时离线联邦分析&#xff0c;低成本、高时效、快速构筑企业实时数据仓…

【MySQL索引与优化篇】InnoDB数据存储结构

文章目录 1. 数据库的存储结构:页1.1 磁盘与内存交互基本单位:页1.2 页结构概述1.3 页的上层结构 2. 页的内部结构3. InnoDB行格式(或记录格式)3.1 Compact行格式3.2 Dynamic和Compressed行格式3.3 Redundant行格式 4. 区、段与碎片区4.1 为什么要有区&#xff1f;4.2 为什么要…

vue手动拖入和导入excel模版

1.列表按钮 <el-button click“importExcel(scope.row.id)” size“small” type“text”>导入excel模版 2.按钮弹框 3.data定义数据 data () { return { projectId: ‘’, importDialogVisible: false, fileList: [], //手动上传 upload_file: ‘’, //导入excel模版…

35二叉树-树的最小深度

目录 LeetCode之路——111. 二叉树的最小深度 分析 解法一&#xff1a;广度优先查询 解法二&#xff1a;深度优先查询 LeetCode之路——111. 二叉树的最小深度 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说…

Visual Studio(VS)C++项目 管理第三方依赖库和目录设置

发现很多程序员存在这种做法&#xff1a;把项目依赖的第三方库的lib和dll放在项目目录下&#xff0c;或者复制到输出目录&#xff0c;因为每种配置都有不同的输出目录&#xff0c;所以要复制多份&#xff08;至少包括Debug和Release两个输出目录&#xff09;&#xff0c;这些做…