LRU和LFU算法

article/2025/10/16 23:40:52

LRU淘汰算法

LRU:Least Recently Used,最近最少使用。即淘汰掉最近最少使用的数据。
以时间轴作为走向:
在这里插入图片描述
如果数据A刚被访问,那么A就应该调至头部:
在这里插入图片描述
假如内存容量已满,现在新数据E被插入,需要淘汰一条数据,那么只需要从尾部开始淘汰,即B被淘汰,E插入头部:
在这里插入图片描述
上面的时间轴可以用双向链表来表示,可以方便的调整数据位置。但是链表的查询效率较低,所以可以在用一个Map作为查询使用,查询复杂度为O(1)。这样下面的数据结构就能完美实现LRU缓存淘汰策略了:
在这里插入图片描述
1. 新数据插入:追加到链表尾部。
2. 如果缓存容量已满,则从头部删除后再在头部插入数据。
3. 缓存中的数据再次被访问:将该节点移至尾部。

力扣LRU题解

原题:

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
1. LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
2. int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
3. void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
* 示例:
输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]
* 解释:
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4
提示:
1 <= capacity <= 3000
0 <= key <= 3000
0 <= value <= 104
最多调用 3 * 104 次 get 和 put

题解:

  • 代码实现:
class LRUCache {//缓存节点private class CacheNode{CacheNode prev;CacheNode next;int key;int value;private CacheNode(int key,int value){this.key = key;this.value = value;this.prev = null;this.next = null;}}//缓存容量private int capacity;//key与节点映射private Map<Integer,CacheNode> valNodeMap;private CacheNode head = new CacheNode(-1,-1);private CacheNode tail = new CacheNode(-1,-1);public LRUCache(int capacity) {this.capacity = capacity;valNodeMap = new HashMap(capacity);this.head.next = tail;this.tail.prev = head;}public int get(int key) {if(!valNodeMap.containsKey(key)){return -1;}CacheNode node = valNodeMap.get(key);node.prev.next = node.next;node.next.prev = node.prev;moveToTail(node);return node.value;}public void put(int key, int value) {if(get(key)!=-1){valNodeMap.get(key).value = value;return;}CacheNode node = new CacheNode(key,value);if(valNodeMap.size() == capacity){//淘汰valNodeMap.remove(head.next.key);head.next.next.prev = head;head.next = head.next.next;}valNodeMap.put(key,node);//追加moveToTail(node);}public void moveToTail(CacheNode node){node.prev = this.tail.prev;this.tail.prev.next = node;node.next = this.tail;this.tail.prev = node;}
}/*** Your LRUCache object will be instantiated and called as such:* LRUCache obj = new LRUCache(capacity);* int param_1 = obj.get(key);* obj.put(key,value);*/

LFU淘汰算法

LFU算法:即最不经常使用淘汰算法。缓存数据会记录被访问的次数,每次被访问次数加一,当需要淘汰数据时,会淘汰使用次数最少的缓存数据。

数据结构

使用一个map作为数据查询,同时也需要一个map用于缓存淘汰,如下图,两个链表即表述缓存淘汰map,该map的value存储的是一个双向链表,链表中是相同使用次数的数据。

  1. 数据插入:在相应次数的链表中头节点插入。
  2. 缓存淘汰:从使用次数最小的链表尾部删除缓存数据。
  3. 数据访问:使用次数加1,原有次数链表中移除,添加到新的链表中。
    在这里插入图片描述

代码实现:

package com.hiwe.demo.cache;import java.util.HashMap;
import java.util.Map;public class LfuCache {//缓存容器private Map<String,Node> cache;//用于存储缓存数据使用次数private Map<Integer,DoubleLinkedList> useTimes;//容量大小private Integer capacity;//已使用容量private Integer useCap = 0;//全局数据最少使用次数private Integer minUseTimes = 1;public LfuCache(Integer capacity){cache = new HashMap<>();this.capacity = capacity;useTimes = new HashMap<>();}/*** 添加数据* @param key* @param value* @return*/public boolean put(String key,String value){Node node = cache.get(key);if(node==null){node = new Node(key,value);cache.put(key,node);useCap++;if(useCap>capacity){//缓存淘汰eliminate();}}else{node.value=value;node.times++;}//次数增加addTimes(node);return true;}/*** 获取数据* @param key* @return*/public String get(String key){Node node = cache.get(key);if(node==null){return null;}//添加到对应次数的链表中node.times++;addTimes(node);return node.value;}/*** 缓存数据淘汰*/private void eliminate(){DoubleLinkedList linkedList = useTimes.get(minUseTimes);String key = linkedList.remove();cache.remove(key);}/*** 数据访问次数添加* @param node*/private void addTimes(Node node){int times = node.times;DoubleLinkedList link = useTimes.get(times);if(link==null){link = new DoubleLinkedList();useTimes.put(times,link);}link.put(node);//记录当前存在数据的最小访问次数if(times>1){DoubleLinkedList preLink = useTimes.get(times-1);preLink.delSize();if(times-1<minUseTimes&&preLink.size>0){minUseTimes=times-1;}}}private class DoubleLinkedList{private Integer size=0;private Node head = new Node(null,null);private Node tail = new Node(null,null);public DoubleLinkedList(){head.next = tail;tail.pre = head;}public void put(Node node){//如果之前存在,则从之前链删除if(node.pre!=null&&node.next!=null){node.pre.next=node.next;node.next.pre = node.pre;}//添加到链表中size++;Node temp = head.next;head.next = node;node.pre = head;node.next = temp;temp.pre = node;}/*** 移除节点* @return key*/public String remove(){Node temp = tail.pre;tail.pre = temp.pre;temp.pre.next = tail;temp.pre=null;temp.next=null;return temp.key;}public void delSize(){size--;}}/*** 数据节点*/private class Node{private String key;private String value;private Integer times = 1;private Node pre=null;private Node next=null;public Node(String key,String value){this.key = key;this.value = value;}}
}

测试代码:

package com.hiwe.demo.cache;public class TestCache {public static void main(String[] args) {LfuCache lfuCache = new LfuCache(2);lfuCache.put("bbb","bbb");lfuCache.put("aaa","aaa");lfuCache.get("bbb");lfuCache.put("ccc","ccc");System.out.println(lfuCache.get("aaa"));System.out.println(lfuCache.get("bbb"));System.out.println(lfuCache.get("ccc"));}
}

http://chatgpt.dhexx.cn/article/sryUucqD.shtml

相关文章

FIFO、LRU、LFU的含义和原理

FIFO&#xff1a;First In First Out&#xff0c;先进先出LRU&#xff1a;Least Recently Used&#xff0c;最近最少使用 LFU&#xff1a;Least Frequently Used&#xff0c;最不经常使用 以上三者都是缓存过期策略。 原理和实现&#xff1a; 一、FIFO按照“先进先出&#…

LFU算法

LFU&#xff08;LeastFrequently Used&#xff09;&#xff0c;即最近最多使用算法。它是基于“如果一个数据在最近一段时间内使用次数很少&#xff0c;那么在将来一段时间内被使用的可能性也很小”的思路。LFU算法需要维护一个队列记录所有数据的访问记录&#xff0c;每个数据…

Redis精通系列——LFU算法详述(Least Frequently Used - 最不经常使用)

本文已收录于专栏 ❤️《Redis精通系列》❤️ 上千人点赞收藏&#xff0c;全套Redis学习资料&#xff0c;大厂必备技能&#xff01; 目录 1、简介 2、实现方式 2.1 LRU实现方式 2.2 LFU实现方式 3、LFU使用 3.1 配置文件开启LFU淘汰算法 1、简介 LRU有一个明显的缺点&…

什么是LRU?什么是LFU

缓存算法是指令的一个明细表&#xff0c;用于决定缓存系统中哪些数据应该被删去。 常见类型包括LFU、LRU、ARC、FIFO、MRU。 最不经常使用算法&#xff08;LFU&#xff09;&#xff1a; 这个缓存算法使用一个计数器来记录条目被访问的频率。通过使用LFU缓存算法&#xff0c;…

LRU算法和LFU算法

文章目录 1、LRU算法2、LFU算法 1、LRU算法 LRU是Least Recently Used的缩写&#xff0c;即最近最少使用&#xff0c;是一种常用的页面置换算法&#xff0c;选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段&#xff0c;用来记录一个页面自上次被访问以来所…

LRU算法与LFU算法

LRU算法 LRU是Least Recently Used的缩写&#xff0c;即最近最少使用算法&#xff0c;是操作系统中页面置换算法的一种&#xff0c;由于内存中存放的页数有限&#xff0c;所以将最近没有使用到的算法会移出内存。 LRU原理&#xff1a; LRU原理如下图所示&#xff1a; 它会将最…

【算法】LFU及其优化

文章目录 什么是LFU&#xff1f;设计思路代码实现&#xff08;基础版本&#xff09;参考论文代码实现&#xff08;优化版本&#xff09;区别 什么是LFU&#xff1f; LRU及其实现 上文讲解了LRU&#xff0c;他是一个基于最近是否被访问来做缓存淘汰的策略。 那么今天介绍一个新…

LRU和LFU算法解析

文章目录 LRU和LFU算法解析LRULRU概念LRU算法实现LRU算法描述LRU算法图示LRU C代码代码测试 LFULFU概念LFU算法实现LFU算法描述LFU算法图示LFU C代码代码测试 总结 LRU和LFU算法解析 LRU LRU概念 LRU&#xff08;The Least Recently Used&#xff0c;最近最少未使用&#xf…

LRU和LFU的区别

对于web开发而言&#xff0c;缓存必不可少&#xff0c;也是提高性能最常用的方式。无论是浏览器缓存(如果是chrome浏览器&#xff0c;可以通过chrome:://cache查看)&#xff0c;还是服务端的缓存(通过memcached或者redis等内存数据库)。缓存不仅可以加速用户的访问&#xff0c;…

LFU算法族:LFU算法

LFU算法族相关文章目录汇总&#xff1a; LFU算法&#xff08;本文&#xff09;​​​​​​​ LFU-Aging算法 window-LFU算法 1、原理 LFU&#xff08;Least Frequently Used&#xff09;算法&#xff0c;即最少访问算法&#xff0c;根据访问缓存的历史频率来淘汰数据&…

LFU算法详解

LFU算法&#xff1a;least frequently used&#xff0c;最近最不经常使用算法 对于每个条目&#xff0c;维护其使用次数 cnt、最近使用时间 time。 cache容量为 n&#xff0c;即最多存储n个条目。 那么当我需要插入新条目并且cache已经满了的时候&#xff0c;需要删除一个之…

算法题就像搭乐高:手把手带你拆解 LFU 算法

f学算法认准labuladong 东哥带你手把手撕力扣???? 点击下方卡片即可搜索???? PS&#xff1a;以后每篇文章最后&#xff0c;labuladong 都会推荐一些自己学过的优质技术专栏&#xff0c;供读者参考。 上篇文章 算法题就像搭乐高&#xff1a;手把手带你拆解 LRU 算法 写了…

LRU LFU 概念、底层原理及其实现 超详细~

0. 前置提要 本篇约为8650字&#xff0c;阅读完需要约40~60分钟。主要介绍页面置换算法,LRU和LFU的原理及其实现&#xff0c;对应leetcode140和460&#xff0c;如果能给个赞就更好了^-^。 1.从内存置换算法说起 计算机的运行的程序和数据保存在内存中&#xff0c;内存的空间是有…

如何实现LFU缓存(最近最少频率使用)

目录 1.什么是LFU缓存&#xff1f; 2.LFU的使用场景有哪些&#xff1f; 3.LFU缓存的实现方式有哪些&#xff1f; 4.put/get 函数实现具体功能 1.什么是LFU缓存&#xff1f; LFU缓存是一个具有指定大小的缓存&#xff0c;随着添加元素的增加&#xff0c;达到容量的上限&…

LFU缓存策略算法

在之前的文章中&#xff0c;我们介绍了如何设计一个LRU算法–如何设计LRU Cache算法&#xff0c;今天我们再聊一聊另一种缓存策略LFU。目前博主个人博客已经搭建发布&#xff0c;后期相关文章也会发布在上面&#xff0c;大家有兴趣可以去上面学习&#xff0c;点击即可前往文青乐…

国内编程学习网站

在本文中&#xff0c;我们介绍了来自两岸三地的编程学习网站&#xff0c;通过它们&#xff0c;不仅可以一窥国内App开发的发展现状&#xff0c;而且这些网站各有特点&#xff0c;无论是主打游戏学习还是视频学习&#xff0c;对于想要自学的开发者而言&#xff0c;都是个好去处。…

如何高效的自学编程

现在的社会对于IT人才的需求越来越大&#xff0c;程序员的薪资水平在各个行业中都算比较高的。所以很多人都想往IT行业发展&#xff0c;已经身处这个行业的人也需要不断的学习新的知识&#xff0c;因为IT行业的技术更新实在是太快了&#xff0c;不像传统行业那样是越老越吃香。…

电脑编程自学(零基础自学编程怎么入门)

电脑编程自学入手:确定编程学习的方向。编程语言有多种:php,C++,C,C#,JAVA,Python等,每种语言都有不同的优缺点,可以根据自己的兴趣方向选择一门编程语言作为自己的学习目标。 基础阶段的语法学习。学习任何一门编程语言,都需要掌握其编程的语法规则,可以通过阅读一…

自学编程的 6 个致命误区

嗨&#xff0c;小伙伴们大家好&#xff0c;我是沉默王二。本篇文章来和大家聊聊自学编程中的一些误区——这是我在 B 站上看了羊哥的一期视频后有感而发的文章。因为确实有很多读者也曾私信问过我这些方面的问题&#xff0c;很有代表性&#xff0c;所以我就结合自己的亲身体会来…

java编程自学app_Java编程自学软件

Java编程自学软件是是一款Java学习软件。Java编程自学软件为用户提供Java语言&#xff0c;ISh和SQL 数据库编程等技术方便用户学习Java知识。有需要自学Java编程的小伙伴们可在华军软件园下载Java编程自学软件。 Java编程自学软件功能特色 专业化、具体化。 有真正意义上的实战…