高级java每日一道面试题-2024年9月30日-算法篇-LRU是什么?如何实现?
如果有遗漏,评论区告诉我进行补充
面试官: LRU是什么?如何实现?
我回答:
LRU(Least Recently Used)是一种常用的缓存淘汰策略,用于在缓存满时决定哪些数据应该被移除。LRU算法的基本思想是:当缓存达到其容量上限时,最近最少使用的数据会被优先淘汰。这种策略假设最近使用的数据在未来也会被频繁访问。
LRU算法概述
LRU算法是一种缓存淘汰策略,其核心思想是:如果一个数据在最近一段时间没有被访问到,那么在未来被访问的可能性也很小。因此,当缓存空间已满时,LRU算法会选择最近最少使用的数据进行淘汰。
LRU算法广泛应用于操作系统中的页面置换、数据库查询优化、Web缓存等场景,是最大化缓存命中率的有效手段之一。
LRU算法的实现原理
LRU的实现
LRU的实现通常需要一个数据结构来同时支持快速查找和插入/删除操作。常用的数据结构是哈希表(HashMap)和双向链表(Doubly Linked List)的结合体。
数据结构
- 哈希表:用于快速查找缓存中的元素。
- 双向链表:用于维护元素的访问顺序,最近访问的元素放在链表头部,最久未访问的元素放在链表尾部。
基本操作
-
插入:
- 如果新插入的键已经在缓存中,则更新其值,并将其移动到链表头部。
- 如果新插入的键不在缓存中,且缓存已满,则移除链表尾部的元素,并将新元素插入到链表头部。
-
访问:
- 如果访问的键在缓存中,则将其移动到链表头部。
- 如果访问的键不在缓存中,则返回null或其他默认值。
-
删除:
- 如果删除的键在缓存中,则从链表和哈希表中移除该元素。
- 如果删除的键不在缓存中,则不进行任何操作。
LRU算法的实现需要满足以下几个要求:
- 查找快:能够迅速找到缓存中的数据。
- 插入快:能够快速地将新数据插入到缓存中。
- 删除快:能够高效地删除缓存中的数据。
- 维护顺序:需要维护数据的访问顺序,以便在缓存空间不足时淘汰最近最少使用的数据。
代码实现
下面是一个使用Java实现LRU缓存的示例:
import java.util.HashMap;
import java.util.Map;public class LRUCache<K, V> {private final int capacity;private final Map<K, Node<K, V>> map;private final DoublyLinkedList<K, V> list;public LRUCache(int capacity) {this.capacity = capacity;this.map = new HashMap<>();this.list = new DoublyLinkedList<>();}public V get(K key) {if (map.containsKey(key)) {Node<K, V> node = map.get(key);list.moveToHead(node); // 将访问的节点移到链表头部return node.value;}return null;}public void put(K key, V value) {if (map.containsKey(key)) {Node<K, V> node = map.get(key);node.value = value; // 更新节点的值list.moveToHead(node); // 将更新的节点移到链表头部} else {if (map.size() >= capacity) {Node<K, V> removedNode = list.removeTail(); // 移除链表尾部的节点map.remove(removedNode.key); // 从哈希表中移除对应的键}Node<K, V> newNode = new Node<>(key, value);list.addHead(newNode); // 将新节点添加到链表头部map.put(key, newNode); // 在哈希表中添加新的键值对}}private static class Node<K, V> {K key;V value;Node<K, V> prev;Node<K, V> next;Node(K key, V value) {this.key = key;this.value = value;}}private static class DoublyLinkedList<K, V> {private Node<K, V> head;private Node<K, V> tail;public void addHead(Node<K, V> node) {if (head == null) {head = tail = node;} else {node.next = head;head.prev = node;head = node;}}public void moveToHead(Node<K, V> node) {if (node == head) return; // 如果节点已经是头结点,则无需移动removeNode(node);addHead(node);}public Node<K, V> removeTail() {if (tail == null) return null;Node<K, V> node = tail;removeNode(tail);return node;}private void removeNode(Node<K, V> node) {if (node.prev != null) {node.prev.next = node.next;} else {head = node.next;}if (node.next != null) {node.next.prev = node.prev;} else {tail = node.prev;}node.prev = null;node.next = null;}}public static void main(String[] args) {LRUCache<Integer, String> cache = new LRUCache<>(2);cache.put(1, "one");cache.put(2, "two");System.out.println(cache.get(1)); // 输出: onecache.put(3, "three"); // 移除最近最少使用的 2System.out.println(cache.get(2)); // 输出: nullcache.put(4, "four"); // 移除最近最少使用的 1System.out.println(cache.get(1)); // 输出: nullSystem.out.println(cache.get(3)); // 输出: threeSystem.out.println(cache.get(4)); // 输出: four}
}
解释
-
LRUCache 类:
capacity:缓存的最大容量。map:哈希表,用于存储键和对应的节点。list:双向链表,用于维护节点的访问顺序。
-
get 方法:
- 如果键存在于缓存中,将对应的节点移动到链表头部,并返回其值。
- 如果键不存在于缓存中,返回null。
-
put 方法:
- 如果键已经存在于缓存中,更新其值并将节点移动到链表头部。
- 如果键不存在于缓存中且缓存已满,移除链表尾部的节点,并将新节点添加到链表头部。
- 如果键不存在于缓存中且缓存未满,直接将新节点添加到链表头部。
-
Node 类:
- 表示双向链表中的一个节点,包含键、值以及前驱和后继指针。
-
DoublyLinkedList 类:
- 实现了双向链表的基本操作,包括添加节点到头部、移动节点到头部、移除节点等。
LRU算法的性能分析
LRU算法的性能主要取决于哈希表和双向链表的操作效率。由于哈希表的查找、插入和删除操作的时间复杂度都是O(1),双向链表的插入、删除和移动操作的时间复杂度也都是O(1)(在已知节点位置的情况下),因此LRU算法的整体时间复杂度可以认为是O(1)。
然而,需要注意的是,在实际应用中,由于哈希表的冲突和链表节点的移动等操作,LRU算法的实际性能可能会受到一定影响。此外,当缓存数据量很大时,哈希表和链表的内存开销也需要考虑。
LRU算法的改进和优化
针对LRU算法的不足,有一些改进和优化方法:
- LRU-K算法:将“最近使用过1次”的判断标准扩展为“最近使用过K次”,以减少缓存污染问题。LRU-K算法需要多维护一个队列来记录所有缓存数据被访问的历史。
- Two Queues(2Q)算法:使用两个缓存队列,一个是FIFO队列,一个是LRU队列。新数据先放入FIFO队列,当数据再次被访问时,将其移到LRU队列。这种算法结合了FIFO和LRU的优点。
- MQ算法:根据访问频率将数据划分为多个队列,不同的队列具有不同的访问优先级。新数据放入最低优先级的队列,当数据的访问次数达到一定次数时,将其提升到更高优先级的队列。
总结
综上所述,LRU算法是一种高效且广泛应用的缓存淘汰策略。在Java中,可以通过使用哈希表和双向链表的组合来实现LRU缓存。同时,也需要根据实际应用场景和需求对LRU算法进行改进和优化。
相关文章:
高级java每日一道面试题-2024年9月30日-算法篇-LRU是什么?如何实现?
如果有遗漏,评论区告诉我进行补充 面试官: LRU是什么?如何实现? 我回答: LRU(Least Recently Used)是一种常用的缓存淘汰策略,用于在缓存满时决定哪些数据应该被移除。LRU算法的基本思想是:当缓存达到其容量上限时࿰…...
CSS选择器的全面解析与实战应用
CSS选择器的全面解析与实战应用 一、基本选择器1.1 通配符选择器(*)2.标签选择器(div)1.3 类名选择器(.class)4. id选择器(#id) 二、 属性选择器(attr)三、伪…...
vue3自动暴露element-plus组件的ref
自动暴露子组件的方法,注意在TS下,需要自己声明类型,我这里全用any代替了 <template><el-button click"getFocus">获得焦点</el-button><com ref"comRef" /> </template><script setup…...
龙芯+FreeRTOS+LVGL实战笔记(新)——10蜂鸣器嘀嘀嘀
本专栏是笔者另一个专栏《龙芯+RT-Thread+LVGL实战笔记》的姊妹篇,主要的区别在于实时操作系统的不同,章节的安排和任务的推进保持一致,并对源码做了完善与优化,各位可以先到本人主页下去浏览另一专栏的博客列表(目前已撰写36篇,图1所示),再决定是否订阅。此外,也可以…...
微信小程序-数据模型与动态赋值
首先新建一个小程序项目. 这边有创建基础项目的流程:从0新建一个微信小程序实现一个简单跳转_小白开发小程序源代码-CSDN博客 一共两步: 1.建立页面的 数据模型 和 默认赋值: 默认赋值: 2.接收输入框的新文案,动态替换上面的文案展示 //文件 testUI.js增加方法:onInputChan…...
【Redis】Linux下安装配置及通过C++访问Redis
文章目录 一、Linux Centos 7.0版本下的安装及配置二、通过C访问Redis 一、Linux Centos 7.0版本下的安装及配置 通过源来安装,此次安装的版本为 redis 5.0 的,要通过其他源进行安装,首先安装 scl 源 yum install centos-release-scl-rh再安…...
Python 入门教程(4)数据类型 | 4.7、元组
文章目录 一、元组1、定义2、创建3、访问元组元素4、遍历元组5、 前言: 在Python编程中,元组(tuple)是一种内置的数据结构,它提供了一种存储多个项目(元素)的方式,这些项目可以是不同…...
Temu正在吸引越来越多的亚马逊卖家,这个市场Temu蝉联下载榜首
近年来,全球电商市场竞争愈发激烈,各大平台纷纷使出浑身解数,以期在激烈的市场竞争中脱颖而出。 一个来自中国的新兴电商平台——Temu,凭借其独特的市场策略和迅猛的发展势头,正在吸引越来越多的亚马逊卖家。Temu为美国…...
设计原则模式概览
前言 架构设计是软件系统稳定的核心因素,也是程序员晋级架构师的核心因素,建议日常开发过程中针对设计进行深挖与思考 核心 分清楚哪些是稳定的,哪些是变化的(一定有稳定跟变化的成分); 捋清楚哪些是类设计…...
高级主题:接口性能测试与压力测试
在现代软件开发中,确保接口的性能和稳定性是非常重要的。随着用户数量的增加,接口需要能够承受高并发请求,从而保证良好的用户体验。本篇文章将介绍如何使用 Python 工具 Locust 进行接口性能测试和压力测试,分析测试结果…...
python绘制图像
柱状图 import os# 输入想要存储图像的路径 os.chdir(D:)import matplotlib.pyplot as plt import numpy as np # 改变绘图风格 import seaborn as snssns.set(color_codesTrue)cell [gen7, xgspon, 3081GB, vettel, totalplay, other] pvalue [21, 20, 18, 13, 7, 34]width…...
如何修复变砖的手机并恢复丢失的数据
您可能之前听说过“变砖”,但您知道什么是变砖手机吗?正如许多论坛中经常提出的问题一样,我如何知道我的手机是否变砖了?好吧,手机变砖主要有两种类型,即软件变砖和硬变砖。软变砖手机意味着重启后您仍然可…...
服务器使用了代理ip,遇到流量攻击,会对服务器有影响吗
当服务器使用代理IP并遭遇流量攻击(如DDoS攻击)时,仍然会对服务器产生影响。以下是关于这种情况的一些详细分析: 1. 流量攻击的性质 流量攻击的目的是通过发送大量请求来耗尽目标服务器的资源或带宽,导致服务中断或不…...
从存储到人工智能洞察: 利用 MinIO 和 Polars 简化数据管道
将 MinIO 的高性能、可扩展企业对象存储的强大功能与 Polars(闪电般快速的 DataFrame 库)的快速内存数据处理功能相结合,可以显著提高数据管道的性能。在 AI 工作流中尤其如此,其中预处理大型数据集和执行特征选择是关键步骤。在这…...
只需要 1 分钟语音数据实现声音克隆
只需要 1 分钟语音数据实现声音克隆 GPT-SoVITS 是一个基于少量语音数据(1 分钟左右)即可训练出高质量 TTS(文本转语音)模型的开源项目,提供少样本语音克隆能力。目前该开源项目已经获得了 33.2k 的 Star!…...
OpenEuler虚拟机安装保姆级教程 | 附可视化界面
0x00 系统介绍 在 2019 年 7 月 19 日,华为宣布要在年底正式开源 openEuler 操作系统;在半年后的 12 月 31 日,华为正式开源了 openEuler 操作系统,邀请社区开发者共同来贡献。 一年后,截止到 2020 年12 月 25日&…...
表格控件QTableWidget
下面说一下表格的常用方法 行列数目、行表头、列表头 行表头:就是表格控件的第一行,用于设置每一列的标题 列表头:就是表格控件的第一列,用于设置每一行的标题,通常缺省则默认显示行号 设置和获取行列的数目 在添…...
LeetCode236题:二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖…...
虚谷中使用PL/SQL改变模式下所有表的大小写
一、将表名转换为小写 1、原理和思路 首先,我们需要查询出指定模式下的所有表名,在xugu中,数据字典dba_tables包含了当前库下的所有表信息,我们可以使用游标(CURSOR)来遍历这些表名。 2、代码示例如下&am…...
数据挖掘的基本步骤和流程解析:深入洞察与策略实施
一、引言 在数据时代的浪潮中,数据挖掘技术已成为企业洞察市场、优化运营和驱动创新的利器。 它融合了统计学、机器学习、数据库管理和人工智能等领域的先进技术,旨在从海量数据中 提取有价值的信息。 本文将深入探讨数据挖掘的六个基本步骤,…...
腾讯优图视觉模型应用:Youtu-VL-4B-Instruct在内容审核中的实战
腾讯优图视觉模型应用:Youtu-VL-4B-Instruct在内容审核中的实战 每天,互联网上会产生数十亿张图片和视频。对于内容平台来说,如何确保这些内容安全合规,同时控制审核成本,一直是个头疼的问题。传统的人工审核效率低、…...
三维点云到二维图像投影的实战指南:从原理到代码实现
1. 三维点云投影二维图像的核心原理 第一次接触三维点云投影时,我也被各种坐标系转换绕得头晕。后来发现只要抓住一个核心:三维到二维的投影本质上是坐标系转换的接力赛。想象你拿着手机拍照,物体从现实世界到手机屏幕的旅程,就是…...
Granite TimeSeries FlowState R1电商销量预测实战:Vue前端可视化大屏
Granite TimeSeries FlowState R1电商销量预测实战:Vue前端可视化大屏 最近和几个做电商的朋友聊天,他们都在头疼同一个问题:备货。备多了怕压库存,备少了又怕错过销售高峰,眼睁睁看着流量来了却没货可发。传统的经验…...
Qwen3-4B Instruct-2507实际作品:用户说‘我要创业’→商业计划书框架生成
Qwen3-4B Instruct-2507实际作品:用户说‘我要创业’→商业计划书框架生成 1. 引言:当创业想法遇到AI助手 “我要创业!” 这句话背后,往往是一个激动人心的想法,但随之而来的是一连串的现实问题:我的商业…...
Phi-3-mini-128k-instruct实战案例:中小企业技术文档自动解析与结构化提取
Phi-3-mini-128k-instruct实战案例:中小企业技术文档自动解析与结构化提取 1. 项目背景与价值 对于中小企业而言,技术文档管理一直是个令人头疼的问题。工程师们经常需要从大量PDF、Word文档中提取关键信息,手动整理成结构化数据。这个过程…...
LangGPT:革新自然语言编程的结构化提示词框架
LangGPT:革新自然语言编程的结构化提示词框架 【免费下载链接】LangGPT LangGPT: Empowering everyone to become a prompt expert!🚀 Structured Prompt,Language of GPT, 结构化提示词,结构化Prompt 项目地址: https://gitcod…...
保姆级教程:用Docker Compose一键部署带汉化和HTTPS的n8n,并配置反向代理(Nginx)
企业级n8n自动化平台全栈部署实战:从容器编排到安全加固 在数字化转型浪潮中,自动化工作流平台已成为企业降本增效的核心基础设施。n8n作为GitHub上增长最快的开源自动化工具之一,凭借其可视化编排能力和400节点生态,正在重塑企业…...
CTF信息收集入门:从BUUCTF‘粗心的小李’题目看Git泄露的常见利用方式
CTF信息收集实战:Git泄露漏洞的深度利用与防御策略 在CTF竞赛的Web安全赛道上,信息收集能力往往决定着解题的成败。当新手面对看似空白的网页时,常会陷入无从下手的困境——这正是"粗心的小李"这类题目的设计初衷。不同于常规的SQL…...
微信无法登录时的恢复操作
本文记录 OpenClaw 中 openclaw-weixin 插件在登录态丢失、微信链接不可用、扫码登录失败时的恢复流程。2026-03-23 版本 OpenClaw 更新后曾出现微信插件失效,但在 2026-03-24 版本中已恢复。本文目标是先判断问题类型,再选择最小影响的修复方式,避免不必要的全量重装。 一、…...
基于模糊PID的水下航行器运动控制系统研究——Matlab 2016b及以上软件应用、课程报告...
基于模糊PID的水下航行器运动控制系统研究 1.适用软件Matlab 2016b及以上 2.课程报告6500字左右共16页 3.课程报告小报告仿真仿真视频 4.请结合以下图片水下航行器的运动控制一直是海洋工程领域的热门课题。面对复杂多变的洋流扰动和强非线性的水动力特性,传统PID控…...
