目标

LFU 算法是通过存储每个缓存使用的频率,在缓存容量满了之后,删除使用频率最少的缓存来给新的缓存留出空间。

如果多个缓存节点都拥有最少使用频率,则删除最久未使用的节点。

思路

HashMap 以及LinkedHashSet(链表)。

链表中的 Node 需要存储 key, value, frequency。使用一个 HashMap (frequencyTable)存储键值 frequency -> 链表, 另一个 HashMap(cacheTable)存储键值 key -> Node。

定义一个 minFrequency 记录最少使用的频率。

具体操作

对于 get 操作,我们首先使用 key 来获取 cacheTable 中对应的 node:

1, 如果 key 不存在,则直接返回 null。

2, 如果 key 存在,我们直接从 node 所在的链表中移除该节点,从 node 中获取当前的 frequency 值并加1, 把该 node 插入到 frequency+1 对应的链表尾部,判断是否需要更新minFrequency。

对于 put 操作,我们首先使用 key 来获取 cacheTable 中对应的 node:

1. 如果 key 不存在, 如果没有的话,相当于是新加入的缓存,如果缓存已经到达容量,通过 minFrequency 找到并删除最近最少使用的缓存,再进行插入。

2. 如果 key 存在,其实操作等价于 get(key) 操作,唯一的区别就是我们需要将当前的缓存里的值更新为 value。

实现

如果需要线程安全,只需在 get 和 put方法加上 synchronized 修饰符。

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;public class LFUCache<K, V> {class CacheNode {K key;V value;int frequency;CacheNode(K key, V value, int frequency) {this.key = key;this.value = value;this.frequency = frequency;}}private Map<Integer, LinkedHashSet<CacheNode>> frequencyTable = new HashMap<>();private Map<K, CacheNode> cacheTable = new HashMap<>();private int minFrequency;private int capacity;public LFUCache(int capacity) {this.capacity = capacity;this.minFrequency = 0;}public void put(K key, V value) {if (capacity <= 0) {return;}CacheNode node = cacheTable.get(key);if (node != null) {node.value = value;increaseFrequency(node);} else {if (cacheTable.size() == capacity) {removeMinFrequencyNode();}addNewCacheNode(key, value);}}public V get(K key) {if (capacity <= 0) {return null;}CacheNode node = cacheTable.get(key);if (node != null) {increaseFrequency(node);return node.value;}return null;}private void addNewCacheNode(K key, V value) {CacheNode newCacheNode = new CacheNode(key, value, 1);LinkedHashSet<CacheNode> set = frequencyTable.computeIfAbsent(1, k -> new LinkedHashSet<>());set.add(newCacheNode);cacheTable.put(key, newCacheNode);minFrequency = 1;}private void removeMinFrequencyNode() {LinkedHashSet<CacheNode> minFrequencySet = frequencyTable.get(minFrequency);CacheNode minFrequencyNode = minFrequencySet.iterator().next();cacheTable.remove(minFrequencyNode.key);minFrequencySet.remove(minFrequencyNode);if (minFrequencySet.size() == 0) {frequencyTable.remove(minFrequency);}}private void increaseFrequency(CacheNode node) {int of = node.frequency;LinkedHashSet<CacheNode> set = frequencyTable.get(node.frequency);set.remove(node);if (set.isEmpty()) {frequencyTable.remove(of);if (of == minFrequency) {minFrequency++;}}int nf = node.frequency + 1;node.frequency++;LinkedHashSet<CacheNode> newSet = frequencyTable.computeIfAbsent(nf, k -> new LinkedHashSet<>());newSet.add(node);}}

LFU (最不经常使用算法)缓存相关推荐

  1. 操作系统之页面置换算法(FIFO、LFU、LRU、OPT算法)

    操作系统之页面置换算法(FIFO.LFU.LRU.OPT算法) TIPS: 主存:实际上的物理内存. 虚存(虚拟内存):虚拟存储技术.虚拟内存使计算机系统内存管理的一种技术.它使得应用程序认为它拥有的 ...

  2. 面试官:你知道 LRU算法 —— 缓存淘汰算法吗?

    常用缓存提升数据查询速度,由于缓存容量有限,当缓存容量到达上限,就需要删除部分数据挪出空间,这样新数据才可以添加进来.缓存数据不能随机删除,一般情况下我们需要根据某种算法删除缓存数据.常用淘汰算法有 ...

  3. 史上最全Java面试266题:算法+缓存+TCP+JVM+搜索+分布式+数据库

    JAVA基础 JAVA中的几种基本数据类型是什么,各自占用多少字节. String类能被继承吗,为什么. String,Stringbuffer,StringBuilder的区别. ArrayList ...

  4. LRU缓存算法缓存设计和实现

    什么是缓存? 举个例子,去图书馆查资料,一般情况下我们会集中把我们有可能查阅的几本书从书架取下来,放在我们的桌面上,以便交叉查阅,从而避免频繁的从座位上跑到书架旁去取书.在这个例子里,书桌所扮演的就是 ...

  5. 字节二面,让写一个LFU缓存策略算法,懵了

    LRU全称 "Least Recently Used",最近最少使用策略,判断最近被使用的时间,距离目前最远的数据优先被淘汰,作为一种根据访问时间来更改链表顺序从而实现缓存淘汰的算 ...

  6. 高级数据结构与算法 | LFU缓存机制(Least Frequently Used)

    文章目录 LFUCache 结构设计 LFUCache的实现 在之前我写过一篇LRU的博客,如果不了解的建议先看看这篇 高级数据结构与算法 | LRU缓存机制(Least Recently Used) ...

  7. 常用缓存淘汰算法(LFU、LRU、ARC、FIFO、MRU)

    缓存算法是指令的一个明细表,用于决定缓存系统中哪些数据应该被删去. 常见类型包括LFU.LRU.ARC.FIFO.MRU. 最不经常使用算法(LFU): 这个缓存算法使用一个计数器来记录条目被访问的频 ...

  8. mysql缓存淘汰机制_聊聊缓存淘汰算法-LRU 实现原理

    前言 我们常用缓存提升数据查询速度,由于缓存容量有限,当缓存容量到达上限,就需要删除部分数据挪出空间,这样新数据才可以添加进来.缓存数据不能随机删除,一般情况下我们需要根据某种算法删除缓存数据.常用淘 ...

  9. 算法高级(11)-缓存淘汰算法研究

    缓存是一个计算机思维,对于重复的计算,缓存其结果,下次再算这个任务的时候,不去真正的计算,而是直接返回结果,能加快处理速度.当然有些会随时间改变的东西,缓存会失效,得重新计算. 一.缓存淘汰算法定义 ...

  10. 【LeetCode】460 and 1132(LFU缓存机制)

    LRU 算法的淘汰策略是 Least Recently Used,也就是每次淘汰那些最久没被使⽤的数据: ⽽ LFU 算法的淘汰策略是 Least Frequently Used,也就是每次淘汰那些使 ...

最新文章

  1. iOS下bound,center和frame
  2. linux安装完redis之后log会在,Linux安装redis logstash
  3. 开发过程真相...太真实了!一毛一样有没有!
  4. Spring Cloud 2020.0.5 发布
  5. setDrawingCacheEnabled(boolean flag)
  6. 你绝对想不到R文件找不到(cannot resolve symbol R)的原因
  7. C#中的命名空间和程序集
  8. pytorch中上采样的实现
  9. asp.net 递归删除文件夹及其子文件夹和所有文件[转]
  10. 深度linux安装make,linux下安装python3完整教程(依赖环境gcc,make,cmake,configure等详细解释)...
  11. JS对cookie进行操作
  12. python怎样清除csv中的数据_使用d清除CSV文件中的数据
  13. go语言--竞争、原子函数、互斥锁
  14. Linux之镜像源篇
  15. 支付宝微信QQ钱包收款码合并教程及源码下载
  16. 地理编码的概念及作用
  17. pycharm 中 import sys 失败的原因 (python)
  18. python生成vcf通讯录文件
  19. 基于SSM框架实现的疫情统计系统
  20. 基于单片机的智能花盆

热门文章

  1. win10输入法中文模式全角半角切换bug解决
  2. 高考成绩查询2021年手机查,2021年全国高考查分系统
  3. python 引用计数 循环引用_Python对象的循环引用问题
  4. 将数组变成json格式
  5. SweetAlert2 使用过程中弹框报错问题记录与解决
  6. Android O版本特性
  7. Spring生命周期详解 + 应用实例
  8. vue中watched属性
  9. db2锁表后如何解锁_DB2解除锁表
  10. code block怎样导入整个文件夹_怎样制作音乐相册?多种风格的背景音乐任你挑...