理解和实现 LFU 缓存置换算法

引言

在计算机科学中,缓存是一种重要的技术,用于提高数据访问速度和系统性能。然而,由于缓存空间有限,当缓存满了之后,就需要一种智能的策略来决定哪些数据应该保留,哪些应该被淘汰。LFU(Least Frequently Used,最少使用)算法就是一种常见的缓存淘汰策略,它基于数据项的访问频率来进行优化管理。

LFU算法简介

LFU算法的核心思想是优先淘汰那些访问频率最低的数据项。在缓存达到容量限制时,LFU算法会移除那些被访问次数最少的缓存条目。如果多个条目的访问次数相同,则根据它们最早被访问的时间进行决策,优先删除最早被访问的条目。

LFU算法的工作原理

LFU算法通常需要两种数据结构来实现:

哈希表:提供O(1)时间复杂度的数据访问和插入。此时哈希表需要两个,一个记录key和当前节点的映射,一个记录频率和节点的映射
双向链表:维护数据项的使用顺序,最近使用的在头部,最久未使用的在尾部。

数据访问和插入的流程如下:

获取数据(Get):从缓存中获取数据,如果数据存在(缓存命中),则更新数据使用的频率,也就是频率+1,同时要删除当前节点之前对应的频率映射;如果数据不存在(缓存未命中),返回 -1。
插入数据(Put):将数据放入缓存,如果数据已经存在,则更新数据值并更新数据使用的频率;如果数据不存在,则将数据插入放入缓存中,并将最低频率设置为1。如果缓存已满,首先需要移除缓存中的元素,然后再插入。

LFU算法的实现

import java.util.HashMap;public class LFUCache {static class Node{int key, value, freq = 1;Node prev, next;Node(int key, int value){this.key = key;this.value = value;}}// 键到节点的映射private HashMap<Integer, Node> keyToNode = new HashMap<>();// 频率到虚拟头节点的映射private HashMap<Integer, Node> freqToDummy = new HashMap<>();// 最小访问频率private int minFreq;// 容量private int capacity;public LFUCache(int capacity) {this.capacity = capacity;}private Node newList() {Node dummy = new Node(0, 0);dummy.prev = dummy;dummy.next = dummy;return dummy;}/*** 根据键获取值。* 该方法首先尝试从keyToNode映射中获取给定键对应的节点。如果节点不存在,说明该键不存在于数据结构中,方法将返回-1。* 如果节点存在,则该方法会执行删除操作(del)和频率更改操作(changeFreq),然后再返回节点的值。* 这种设计可能是为了在获取值的同时,根据获取情况动态调整数据结构,例如实现一种基于频率的缓存淘汰策略。** @param key 需要获取值的键。* @return 键对应的值,如果键不存在,则返回-1。*/public int get(int key) {// 尝试从映射中获取给定键对应的节点。Node node = keyToNode.get(key);// 如果节点不存在,说明键不存在于数据结构中,返回-1。if(node == null) return -1;// 修改节点的频率信息,changeFreq(node);// 返回节点的值。return node.value;}/*** 插入一个键值对到缓存中。* 如果键已经存在,则更新其值,并根据更新后的频率进行调整。* 如果缓存已满,则移除最低频率的键值对,并插入新的键值对。** @param key 插入或更新的键。* @param value 插入或更新的值。*/public void put(int key, int value) {// 尝试从映射中获取现有的节点Node node = keyToNode.get(key);if(node != null){// 如果节点存在,更新其值,并准备进行频率更新操作node.value = value;changeFreq(node);return;}// 如果缓存已满,需要移除最低频率的节点以腾出空间if(keyToNode.size() == capacity){Node cur = freqToDummy.get(minFreq);Node delNode = cur.prev;keyToNode.remove(delNode.key);del(delNode);if(cur.prev == cur) freqToDummy.remove(minFreq);}// 创建新节点,并插入到映射和频率链表中node = new Node(key, value);keyToNode.put(key, node);insert(1, node);minFreq = 1;}/*** 修改节点的频率。* 此方法用于更新给定节点的频率,并相应地调整频率列表和最小频率的值。* 如果更新后的频率导致原有的频率列表头部节点成为一个孤立节点(即它的前向和后向指针都指向自己),* 则该节点将从频率列表中移除,并且如果该频率原本是最低频率,则最小频率值将增加。* 最后,使用更新后的频率将节点插入到频率列表的适当位置。** @param node 需要更新频率的节点。*/void changeFreq(Node node){// 1、先删除节点del(node);// 根据当前节点的频率获取频率链表的头部节点Node cur = freqToDummy.get(node.freq);// 检查当前频率的链表是否为空(即头部节点的前向指针是否指向自己)if(cur.prev == cur){// 如果链表为空,则从映射中移除该频率,并检查是否需要调整最小频率值freqToDummy.remove(node.freq);if(minFreq == node.freq){minFreq++;}}// 3、插入到新位置insert(++node.freq, node);}/*** 将给定节点插入到特定频率链表中。* 此函数假设频率对应的链表已经存在,或者如果不存在,则会创建一个新的链表。* 插入操作在链表的头部进行,以保持节点按频率排序。** @param key 节点的键值,用于确定节点应插入到哪个频率链表。* @param node 要插入的节点。*/void insert(int key, Node node){// 根据频率获取或创建对应的频率链表的头节点。// 获取频率的头节点Node cur = freqToDummy.computeIfAbsent(key, k -> newList());node.prev = cur;node.next = cur.next;cur.next.prev = node;cur.next = node;}/*** 从双向链表中删除给定节点。* 此函数不返回任何值,因为它操作的是链表的内部结构。* 它接受一个参数 node,该参数是需要被删除的节点。** @param node 需要被删除的节点。*/void del(Node node){/* 将给定节点的前一个节点的next指针指向给定节点的后一个节点,从而在链表中向前断开给定节点。 */node.next.prev = node.prev;/* 将给定节点的后一个节点的prev指针指向给定节点的前一个节点,从而在链表中向后断开给定节点。 */node.prev.next = node.next;}}

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

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

相关文章

FLASH闪存

FLASH闪存 程序现象&#xff1a; 1、读写内部FLASH 这个代码的目的&#xff0c;就是利用内部flash程序存储器的剩余空间&#xff0c;来存储一些掉电不丢失的参数。所以这里的程序是按下K1变换一下测试数据&#xff0c;然后存储到内部FLASH&#xff0c;按下K2把所有参数清0&…

找不到mfc140u.dll怎么修复,mfc140u.dll丢失的多种修复方法

计算机丢失mfc140u.dll文件会导致依赖该文件的软件无法正常运行。mfc140u.dll是Microsoft Visual C 2015的可再发行组件之一&#xff0c;它属于Microsoft Foundation Class (MFC) 库&#xff0c;许多使用MFC开发的程序需要这个DLL文件来正确执行。丢失了mfc140u.dll文件。会导致…

无人机无刷电机理论教学培训课程

本文档为一份关于Brushless电机理论的详细教程&#xff0c;由TYTO Robotics编制&#xff0c;旨在帮助用户理解brushless电机的工作原理、特性以及如何通过实验测定其关键参数Kv和Kt。文档首先介绍了brushless电机的基本组成&#xff0c;包括静止的定子和旋转的转子&#xff0c;…

AR增强现实在桥梁工程专业课堂上的应用

桥梁工程专业课堂上应用增强现实技术具有多方面的优势。首先&#xff0c;增强现实技术能够提供更加直观、生动、真实的桥梁工程学习环境&#xff0c;使学生能够更好地理解和掌握桥梁工程的基本原理和设计方法。其次&#xff0c;增强现实技术能够提供更加丰富的桥梁工程案例和实…

考研数学|线代零基础,听谁的课比较合适?

线性代数是数学的一个重要分支&#xff0c;对于考研的学生来说&#xff0c;掌握好这门课程是非常关键的。由于你之前没有听过线性代数课&#xff0c;选择一个合适的课程和老师就显得尤为重要。 以下是一些建议&#xff0c;希望能帮助你找到合适的课程资源。 首先&#xff0c;…

Hadoop3:MapReduce中的ETL(数据清洗)

一、概念说明 “ETL&#xff0c;是英文Extract-Transform-Load的缩写&#xff0c;用来描述将数据从来源端经过抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;、加载&#xff08;Load&#xff09;至目的端的过程。ETL一词较常用在数据仓库&#…

python学习 - 设计模式 - 状态模式

大话设计模式 设计模式——状态模式 状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为&#xff0c;这个对象看起来像是改变了其类 应用场景:当控制一个对象的状态转换的条件表达式过于复杂时,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的…

LED显示屏的点间距越小越好吗

引言 在LED显示屏市场日趋成熟的同时&#xff0c;小间距显示屏成为了许多用户的首选。然而&#xff0c;点间距真的是越小越好吗&#xff1f;本文将探讨这一问题&#xff0c;并提供全面的选购指南。 点间距&#xff1a;并非越小越好 小间距显示屏因其精细的显示效果而备受青睐。…

剪辑如何剪辑制作视频短视频剪辑学习怎么学,难吗?

工欲善其事必先利其器&#xff0c;有一个好的工具能让你的工作如鱼得水&#xff0c;果你想在短视频中制作精良的视频&#xff0c;你就考虑电脑制作软件了。果你想制作精良的视频&#xff0c;你就考虑电脑制作软件了。 如何找到剪辑软件了&#xff1f;你可以直接去软件的官方。你…

KT6368A-sop8蓝牙主机芯片获取电动车胎压传感器数据功能

KT6368A蓝牙芯片新增主机模式&#xff0c;扫描周边的胎压传感器&#xff0c;这里扮演的角色就是观察者。因为测试胎压传感器&#xff0c;发现它的广播模式可发现&#xff0c;不可连接 胎压传感器部分的手册说明如下&#xff0c;关于蓝牙部分的协议 实际蓝牙芯片收到的数据&…

国密算法SM1 SM2 SM3 SM4 SM9

一、概述 SM1-无具体实现 SM1作为一种对称加密算法&#xff0c;由于其算法细节并未公开&#xff0c;且主要在中国国内使用&#xff0c;因此在国际通用的加密库&#xff08;如Bouncy Castle&#xff09;中并不直接支持SM1算法。 SM1算法的具体实现涉及国家密码管理局的规范&…

Studying-代码随想录训练营day20| 235.二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

第二十天&#xff0c;二叉树part07&#xff0c;二叉树搜索树加油加油&#x1f4aa; 目录 235.二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点 拓展&#xff1a;普通二叉树的删除方式 总结 235.二叉搜索树的最近公共祖先 文档讲解&…

洁净室(区)浮游菌检测标准操作规程及GB/T 16292-2010测试方法解读

洁净室(区)空气中浮游菌的检测。洁净区浮游菌检测是一种评估和控制洁净区(如实验室、生产车间等)内空气质量的方法。这种检测的目的是通过测量空气中的微生物(即浮游菌)数量&#xff0c;来评估洁净区的清洁度或污染程度。下面中邦兴业小编带大家详细看下如何进行浮游菌采样检测…

RK3568技术笔记九 编译Linux详细介绍

在编译前需要按照前面的方法始化编译环境&#xff0c;否则会导致编译失败&#xff08;若配置过则无需重复配置&#xff09;。 全自动编译包含所有镜像编译&#xff0c;包括&#xff1a;uboot编译、Kernel编译、Recovey编译、文件系统编译、编译完成镜像的更新与打包。 按照前面…

阅读笔记——《Large Language Model guided Protocol Fuzzing》

【参考文献】Meng R, Mirchev M, Bhme M, et al. Large language model guided protocol fuzzing[C]//Proceedings of the 31st Annual Network and Distributed System Security Symposium (NDSS). 2024.&#xff08;CCF A类会议&#xff09;【注】本文仅为作者个人学习笔记&a…

【附精彩文章合辑】当谈到程序的“通用性”与“过度设计”的困境时,我们可以通过一些具体的例子来更直观地阐述这些解决方案

当谈到程序的“通用性”与“过度设计”的困境时&#xff0c;我们可以通过一些具体的例子来更直观地阐述这些解决方案。以下是一些示例&#xff1a; 一、明确需求与目标 例子1&#xff1a;在线购物平台 需求分析&#xff1a;平台需要支持用户注册、登录、浏览商品、下单购买、…

2024ciscn 华东北awdp pwn部分wp

pwn1 break 很简单&#xff0c;栈可执行。 先格式化字符串泄露出栈地址和canary&#xff0c;然后稍稍布置一下打orw就行 沙盒和没有一样 from pwn import *context(archamd64, oslinux)if __name__ __main__:# io remote(192.47.1.39, 80)io remote(192.168.142.137, 123…

初阶 《操作符详解》 10. 逗号表达式

10. 逗号表达式 exp1, exp2, exp3, …expN 注&#xff1a; 1.逗号表达式&#xff0c;就是用逗号隔开的多个表达式 2.逗号表达式&#xff0c;从左向右依次执行&#xff0c;整个表达式的结果是最后一个表达式的结果 代码1 #include <stdio.h> int main() {int a 1;int b…

【Qt6.3 基础教程 19】 设计直观用户界面(UI):Qt应用界面设计原则

文章目录 前言理解用户需求界面的简洁性一致性反馈利用布局管理美化你的应用结论 前言 用户界面(UI)设计对于任何软件项目的成功至关重要&#xff0c;因为它是用户与您的应用之间交流的桥梁。在Qt环境中&#xff0c;拥有一套清晰和直观的UI设计原则&#xff0c;将有助于您创建…

解决ubuntu18.04 安装vscode 报依赖库错误,以及打不开终端的问题。

其实很简单&#xff0c;ubuntu18.04太老了&#xff0c;官网最新版本的vscode对ubuntu18.04会有些依赖库的问题。 一顿查资料后发现2023.11月的1.85版本正常使用&#xff0c;于是完美解决。 下载链接 Visual Studio Code November 2023 点击这里下载。 下载完成&#xff0c;…