当前位置: 首页 > news >正文

高级java每日一道面试题-2024年9月30日-算法篇-LRU是什么?如何实现?

如果有遗漏,评论区告诉我进行补充

面试官: LRU是什么?如何实现?

我回答:

LRU(Least Recently Used)是一种常用的缓存淘汰策略,用于在缓存满时决定哪些数据应该被移除。LRU算法的基本思想是:当缓存达到其容量上限时,最近最少使用的数据会被优先淘汰。这种策略假设最近使用的数据在未来也会被频繁访问。

LRU算法概述

LRU算法是一种缓存淘汰策略,其核心思想是:如果一个数据在最近一段时间没有被访问到,那么在未来被访问的可能性也很小。因此,当缓存空间已满时,LRU算法会选择最近最少使用的数据进行淘汰。

LRU算法广泛应用于操作系统中的页面置换、数据库查询优化、Web缓存等场景,是最大化缓存命中率的有效手段之一。

LRU算法的实现原理

LRU的实现

LRU的实现通常需要一个数据结构来同时支持快速查找和插入/删除操作。常用的数据结构是哈希表(HashMap)和双向链表(Doubly Linked List)的结合体。

数据结构
  • 哈希表:用于快速查找缓存中的元素。
  • 双向链表:用于维护元素的访问顺序,最近访问的元素放在链表头部,最久未访问的元素放在链表尾部。
基本操作
  1. 插入

    • 如果新插入的键已经在缓存中,则更新其值,并将其移动到链表头部。
    • 如果新插入的键不在缓存中,且缓存已满,则移除链表尾部的元素,并将新元素插入到链表头部。
  2. 访问

    • 如果访问的键在缓存中,则将其移动到链表头部。
    • 如果访问的键不在缓存中,则返回null或其他默认值。
  3. 删除

    • 如果删除的键在缓存中,则从链表和哈希表中移除该元素。
    • 如果删除的键不在缓存中,则不进行任何操作。

LRU算法的实现需要满足以下几个要求:

  1. 查找快:能够迅速找到缓存中的数据。
  2. 插入快:能够快速地将新数据插入到缓存中。
  3. 删除快:能够高效地删除缓存中的数据。
  4. 维护顺序:需要维护数据的访问顺序,以便在缓存空间不足时淘汰最近最少使用的数据。

代码实现

下面是一个使用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}
}

解释

  1. LRUCache 类

    • capacity:缓存的最大容量。
    • map:哈希表,用于存储键和对应的节点。
    • list:双向链表,用于维护节点的访问顺序。
  2. get 方法

    • 如果键存在于缓存中,将对应的节点移动到链表头部,并返回其值。
    • 如果键不存在于缓存中,返回null。
  3. put 方法

    • 如果键已经存在于缓存中,更新其值并将节点移动到链表头部。
    • 如果键不存在于缓存中且缓存已满,移除链表尾部的节点,并将新节点添加到链表头部。
    • 如果键不存在于缓存中且缓存未满,直接将新节点添加到链表头部。
  4. Node 类

    • 表示双向链表中的一个节点,包含键、值以及前驱和后继指针。
  5. DoublyLinkedList 类

    • 实现了双向链表的基本操作,包括添加节点到头部、移动节点到头部、移除节点等。

LRU算法的性能分析

LRU算法的性能主要取决于哈希表和双向链表的操作效率。由于哈希表的查找、插入和删除操作的时间复杂度都是O(1),双向链表的插入、删除和移动操作的时间复杂度也都是O(1)(在已知节点位置的情况下),因此LRU算法的整体时间复杂度可以认为是O(1)。

然而,需要注意的是,在实际应用中,由于哈希表的冲突和链表节点的移动等操作,LRU算法的实际性能可能会受到一定影响。此外,当缓存数据量很大时,哈希表和链表的内存开销也需要考虑。

LRU算法的改进和优化

针对LRU算法的不足,有一些改进和优化方法:

  1. LRU-K算法:将“最近使用过1次”的判断标准扩展为“最近使用过K次”,以减少缓存污染问题。LRU-K算法需要多维护一个队列来记录所有缓存数据被访问的历史。
  2. Two Queues(2Q)算法:使用两个缓存队列,一个是FIFO队列,一个是LRU队列。新数据先放入FIFO队列,当数据再次被访问时,将其移到LRU队列。这种算法结合了FIFO和LRU的优点。
  3. MQ算法:根据访问频率将数据划分为多个队列,不同的队列具有不同的访问优先级。新数据放入最低优先级的队列,当数据的访问次数达到一定次数时,将其提升到更高优先级的队列。

总结

综上所述,LRU算法是一种高效且广泛应用的缓存淘汰策略。在Java中,可以通过使用哈希表和双向链表的组合来实现LRU缓存。同时,也需要根据实际应用场景和需求对LRU算法进行改进和优化。

相关文章:

高级java每日一道面试题-2024年9月30日-算法篇-LRU是什么?如何实现?

如果有遗漏,评论区告诉我进行补充 面试官: LRU是什么?如何实现? 我回答: LRU&#xff08;Least Recently Used&#xff09;是一种常用的缓存淘汰策略&#xff0c;用于在缓存满时决定哪些数据应该被移除。LRU算法的基本思想是&#xff1a;当缓存达到其容量上限时&#xff0…...

CSS选择器的全面解析与实战应用

CSS选择器的全面解析与实战应用 一、基本选择器1.1 通配符选择器&#xff08;*&#xff09;2.标签选择器&#xff08;div&#xff09;1.3 类名选择器&#xff08;.class&#xff09;4. id选择器&#xff08;#id&#xff09; 二、 属性选择器&#xff08;attr&#xff09;三、伪…...

vue3自动暴露element-plus组件的ref

自动暴露子组件的方法&#xff0c;注意在TS下&#xff0c;需要自己声明类型&#xff0c;我这里全用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版本下的安装及配置 通过源来安装&#xff0c;此次安装的版本为 redis 5.0 的&#xff0c;要通过其他源进行安装&#xff0c;首先安装 scl 源 yum install centos-release-scl-rh再安…...

Python 入门教程(4)数据类型 | 4.7、元组

文章目录 一、元组1、定义2、创建3、访问元组元素4、遍历元组5、 前言&#xff1a; 在Python编程中&#xff0c;元组&#xff08;tuple&#xff09;是一种内置的数据结构&#xff0c;它提供了一种存储多个项目&#xff08;元素&#xff09;的方式&#xff0c;这些项目可以是不同…...

Temu正在吸引越来越多的亚马逊卖家,这个市场Temu蝉联下载榜首

近年来&#xff0c;全球电商市场竞争愈发激烈&#xff0c;各大平台纷纷使出浑身解数&#xff0c;以期在激烈的市场竞争中脱颖而出。 一个来自中国的新兴电商平台——Temu&#xff0c;凭借其独特的市场策略和迅猛的发展势头&#xff0c;正在吸引越来越多的亚马逊卖家。Temu为美国…...

设计原则模式概览

前言 架构设计是软件系统稳定的核心因素&#xff0c;也是程序员晋级架构师的核心因素&#xff0c;建议日常开发过程中针对设计进行深挖与思考 核心 分清楚哪些是稳定的&#xff0c;哪些是变化的&#xff08;一定有稳定跟变化的成分&#xff09;&#xff1b; 捋清楚哪些是类设计…...

高级主题:接口性能测试与压力测试

在现代软件开发中&#xff0c;确保接口的性能和稳定性是非常重要的。随着用户数量的增加&#xff0c;接口需要能够承受高并发请求&#xff0c;从而保证良好的用户体验。本篇文章将介绍如何使用 Python 工具 Locust 进行接口性能测试和压力测试&#xff0c;分析测试结果&#xf…...

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…...

如何修复变砖的手机并恢复丢失的数据

您可能之前听说过“变砖”&#xff0c;但您知道什么是变砖手机吗&#xff1f;正如许多论坛中经常提出的问题一样&#xff0c;我如何知道我的手机是否变砖了&#xff1f;好吧&#xff0c;手机变砖主要有两种类型&#xff0c;即软件变砖和硬变砖。软变砖手机意味着重启后您仍然可…...

服务器使用了代理ip,遇到流量攻击,会对服务器有影响吗

当服务器使用代理IP并遭遇流量攻击&#xff08;如DDoS攻击&#xff09;时&#xff0c;仍然会对服务器产生影响。以下是关于这种情况的一些详细分析&#xff1a; 1. 流量攻击的性质 流量攻击的目的是通过发送大量请求来耗尽目标服务器的资源或带宽&#xff0c;导致服务中断或不…...

从存储到人工智能洞察: 利用 MinIO 和 Polars 简化数据管道

将 MinIO 的高性能、可扩展企业对象存储的强大功能与 Polars&#xff08;闪电般快速的 DataFrame 库&#xff09;的快速内存数据处理功能相结合&#xff0c;可以显著提高数据管道的性能。在 AI 工作流中尤其如此&#xff0c;其中预处理大型数据集和执行特征选择是关键步骤。在这…...

只需要 1 分钟语音数据实现声音克隆

只需要 1 分钟语音数据实现声音克隆 GPT-SoVITS 是一个基于少量语音数据&#xff08;1 分钟左右&#xff09;即可训练出高质量 TTS&#xff08;文本转语音&#xff09;模型的开源项目&#xff0c;提供少样本语音克隆能力。目前该开源项目已经获得了 33.2k 的 Star&#xff01;…...

OpenEuler虚拟机安装保姆级教程 | 附可视化界面

0x00 系统介绍 在 2019 年 7 月 19 日&#xff0c;华为宣布要在年底正式开源 openEuler 操作系统&#xff1b;在半年后的 12 月 31 日&#xff0c;华为正式开源了 openEuler 操作系统&#xff0c;邀请社区开发者共同来贡献。 一年后&#xff0c;截止到 2020 年12 月 25日&…...

表格控件QTableWidget

下面说一下表格的常用方法 行列数目、行表头、列表头 行表头&#xff1a;就是表格控件的第一行&#xff0c;用于设置每一列的标题 列表头&#xff1a;就是表格控件的第一列&#xff0c;用于设置每一行的标题&#xff0c;通常缺省则默认显示行号 设置和获取行列的数目 在添…...

LeetCode236题:二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它自己的祖…...

虚谷中使用PL/SQL改变模式下所有表的大小写

一、将表名转换为小写 1、原理和思路 首先&#xff0c;我们需要查询出指定模式下的所有表名&#xff0c;在xugu中&#xff0c;数据字典dba_tables包含了当前库下的所有表信息&#xff0c;我们可以使用游标&#xff08;CURSOR&#xff09;来遍历这些表名。 2、代码示例如下&am…...

数据挖掘的基本步骤和流程解析:深入洞察与策略实施

一、引言 在数据时代的浪潮中&#xff0c;数据挖掘技术已成为企业洞察市场、优化运营和驱动创新的利器。 它融合了统计学、机器学习、数据库管理和人工智能等领域的先进技术&#xff0c;旨在从海量数据中 提取有价值的信息。 本文将深入探讨数据挖掘的六个基本步骤&#xff0c…...

BCJR算法——卷积码的最大后验译码

定义&#xff1a;输入序列为 其中每比特&#xff0c;同时相应的输出序列为 其中每一码字的长度为n&#xff0c;定义在i时刻的编码器的状态为&#xff0c;对于时刻里有 表示输出码字和卷积码第i时刻的输入和第i-1时刻的状态有关&#xff08;包括寄存器和输出部分&#xff09;&am…...

系统架构设计师论文《论SOA在企业集成架构设计中的应用》精选试读

论文真题 企业应用集成(Enterprise Application Integration, EAI)是每个企业都必须要面对的实际问题。面向服务的企业应用集成是一种基于面向服务体系结构(Service-OrientedArchitecture,SOA&#xff09;的新型企业应用集成技术&#xff0c;强调将企业和组织内部的资源和业务…...

ceph rgw 桶分片之reshard

Ceph RGW&#xff08;RADOS Gateway&#xff09;的 reshard 功能是用来动态调整对象存储的分片&#xff08;shard&#xff09;数量&#xff0c;从而优化性能和存储利用率。随着数据量的增加&#xff0c;初始的分片设置可能无法满足性能需求&#xff0c;因此 reshard 功能允许用…...

开放原子开源基金会网站上的开源项目Opns存在缓冲区溢出缺陷

最近在开放原子开源基金会网站上&#xff0c;看到一些开源项目&#xff0c;之前分析出华为的鸿蒙操作系统代码&#xff0c;没有发现有价值的安全漏洞。现在&#xff0c;下载上面的Onps开源网络协议栈&#xff0c;既然是通讯所使用的软件&#xff0c;其质量应该值得信任呢&#…...

未来前端发展方向:深度探索与技术前瞻

未来前端发展方向&#xff1a;深度探索与技术前瞻 在数字化浪潮席卷全球的今天&#xff0c;前端开发作为连接用户与数字世界的桥梁&#xff0c;其重要性不言而喻。随着技术的不断进步和市场的不断变化&#xff0c;前端开发领域正经历着前所未有的变革。今天&#xff0c;我们将深…...

前端工程规范-2:JS代码规范(Prettier + ESLint)

Prettier 和 ESLint 是两个在现代 JavaScript 开发中广泛使用的工具&#xff0c;它们结合起来可以提供以下作用和优势&#xff1a; 代码格式化和风格统一&#xff1a; Prettier 是一个代码格式化工具&#xff0c;能够自动化地处理代码的缩进、空格、换行等格式问题&#xff0c;…...

Tomcat为什么要打破双亲委派?怎么保证安全

Tomcat打破双亲委派模型的原因主要是为了解决Web应用程序中的类加载冲突问题&#xff0c;并提供更好的灵活性和可扩展性。在Java中&#xff0c;双亲委派模型是一种类加载机制&#xff0c;它确保了类加载的安全性和一致性&#xff0c;但在Web应用程序的场景下&#xff0c;它可能…...

【C++篇】启航——初识C++(下篇)

接上篇【C篇】启航——初识C&#xff08;上篇&#xff09; 目录 一、引用 1.引用的概念 2.引用的基本语法 3.引用的特点 3.1 别名 3.2 不占用额外内存 3.3 必须初始化 3.4 不能为 NULL 4.引用的使用 4.1 函数参数传递 4.2 返回值 4.3 常量引用 5.引用和指针的关…...

Elasticsearch快速入门

文章目录 Elasticsearch快速入门核心概念倒排索引基本使用索引操作创建索引类型映射[了解]数据类型[了解] 查看索引删除索引 文档操作添加文档修改文档删除文档查询文档准备数据主键查询精确查询匹配查询 Elasticsearch快速入门 核心概念 Elasticsearch是面向文档的&#xff…...

uniapp微信小程序遮罩层u-popup禁止底层穿透

添加 touchmove.prevent&#xff0c;遮罩层底部的页面就不会滑动了微信开发者工具不生效&#xff0c;真机生效 <u-popup :show"showEwm" close"closeEwm" mode"center" touchmove.prevent><view class"ewmshow"></vie…...

程序员自学网站/seo在线教学

BOOL CPrjDlg::PreTranslateMessage(MSG* pMsg){if ((pMsg->message WM_LBUTTONDOWN) || (pMsg->message WM_LBUTTONUP)) //核心点{if (GetFocus() GetDlgItem(IDC_EDIT_PRJ_NAME)) //根据不同控件焦点判断是那个在执行 {char chHelp[100]; GetPrivateProfileStrin…...

改善网站建设/最新seo课程

介绍(2021-05-12)用*好的iOS鼾声分析软件来记录、测量和减少您的鼾声。医生强烈推荐&#xff01;鼾声分析器利用声波分析来测量和记录鼾声&#xff0c;帮助您找出减少鼾声的有效方法。“这个应用是个意外的惊喜。我第一次感觉能够控制打鼾了。谢谢鼾声分析器&#xff01;”“鼾…...

英文版网站建设方案/海外推广服务

文章目录Kubernetes POD 容器升级实战1、查看各pod容器组的容器更新情况2、查看pod组运行情况3、查看部署的信息效果4、容器升级更新5、查看容器升级更新进程6、滚动更新过程详解7、容器版本回滚8、查看是否回滚9、pod容器组采用的镜像历史版本&#xff08;1&#xff09;查看曾…...

淘宝天猫优惠券网站怎么做/百度开户推广多少钱

1、打开Internert信息管理查看IIS是否启动&#xff0c;且默认网站时候已经开启&#xff1b; 2、打开http://127.0.0.1 看是否能访问IIS的默认网页&#xff0c;能访问则说明IIS已经成功安装到电脑上&#xff0c;可能是无法解析localhost&#xff1b; 3、开始--命令&#xff08…...

记事本做网站/专门看网站的浏览器

题图摄于北京奥利匹克公园注&#xff1a;微信公众号不按照时间排序&#xff0c;请关注公众号“亨利笔记”&#xff0c;并加星标以置顶&#xff0c;以免错过更新。本文作者为VMware研发工程师&#xff0c;KubeFATE开源项目维护者。KubeFATE 日志聚合从 KubeFATE v1.5.1开始支持对…...

杀手杰夫链接网站代码/公众号推广引流

众包&#xff08;Crowdsourcing&#xff09;是这样一个过程&#xff1a;征求大批社区中的群众去完成一个任务&#xff0c;传统上这种任务由组织从内部选择一拨人来完成&#xff0c;多数是雇员或合同工。众包测试&#xff08;Crowdsourced testing&#xff09;利用众包的有效性和…...