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

【SSP之路-5-重要节点】LFU

LFU(Least Frequently Used,最近最少使用)缓存是一种高级缓存淘汰算法。与 LRU(最近最少使用)不同,LFU 关注的是数据被访问的频率

如果一个数据在过去被访问的次数越多,那么它在未来被访问的可能性就越大。当缓存满时,LFU 会优先淘汰那些访问次数最少的数据。如果次数相同,则淘汰最久未被访问的数据。


1. 核心挑战:如何做到O(1)O(1)O(1)时间复杂度?

实现 LFU 的难点在于,我们需要在O(1)O(1)O(1)时间内完成:

  1. 查询:通过 Key 获取 Value。
  2. 更新:增加某个 Key 的访问计数,并将其移到新的频率区间。
  3. 淘汰:找到频率最低且最旧的数据并删除。

传统的堆(Heap)结构虽然能找最小值,但更新操作需要O(log⁡n)O(\log n)O(logn)。为了达到O(1)O(1)O(1),我们通常采用双重哈希表 + 双向链表的结构。


2. 数据结构设计

我们需要三个主要组件:

  • Key 到 节点的映射 (key_table):存储 Key 与其对应的值、频率等信息。
  • 频率 到 节点链表的映射 (freq_table):每一层频率(如访问了 1 次、2 次…)都对应一个双向链表,链表内按访问时间排序。
  • 全局最小频率 (min_freq):记录当前缓存中最小的访问频率,方便淘汰时定位。

3. C++ 实现解析

#include<unordered_map>#include<list>structNode{intkey,val,freq;Node(intk,intv,intf):key(k),val(v),freq(f){}};classLFUCache{intcapacity;intmin_freq;// key -> list迭代器 (方便 O(1) 删除)std::unordered_map<int,std::list<Node>::iterator>key_table;// freq -> 该频率下的 Node 链表std::unordered_map<int,std::list<Node>>freq_table;public:LFUCache(intcapacity):capacity(capacity),min_freq(0){}intget(intkey){if(capacity==0||key_table.find(key)==key_table.end())return-1;autoit=key_table[key];intval=it->val;intfreq=it->freq;// 1. 从旧频率链表中移除freq_table[freq].erase(it);if(freq_table[freq].empty()){freq_table.erase(freq);if(min_freq==freq)min_freq++;}// 2. 插入新频率链表 (freq + 1) 的头部freq_table[freq+1].push_front(Node(key,val,freq+1));key_table[key]=freq_table[freq+1].begin();returnval;}voidput(intkey,intvalue){if(capacity==0)return;if(get(key)!=-1){// 如果 key 已存在,get 内部已处理频率更新key_table[key]->val=value;// 更新值即可return;}// 3. 缓存已满,淘汰最小频率链表的末尾元素if(key_table.size()==capacity){autoit=freq_table[min_freq].back();key_table.erase(it.key);freq_table[min_freq].pop_back();if(freq_table[min_freq].empty())freq_table.erase(min_freq);}// 4. 插入新元素,频率设为 1min_freq=1;freq_table[1].push_front(Node(key,value,1));key_table[key]=freq_table[1].begin();}};

4. 算法流程拆解

get(key)发生时:

  1. 通过key_table找到该节点。
  2. 提取值,并将该节点从freq_table[f]中删除。
  3. 将该节点加入到freq_table[f+1]的头部。
  4. 关键:如果旧频率f正好是min_freq且对应的链表空了,则min_freq需要自增。

put(key, value)发生时:

  1. 如果 Key 已存在,更新 Value 并触发一次“访问更新”(同get)。
  2. 如果 Key 不存在:
  • 缓存满了吗?满了就去freq_table[min_freq]末尾(最旧的节点)删掉一个。
  • 插入新节点,频率设为 1。
  • 重置min_freq = 1

5. LRU 与 LFU 的对比

特性LRU (Least Recently Used)LFU (Least Frequently Used)
核心逻辑淘汰最久没被访问的淘汰访问次数最少的
适用场景具有时间局部性的数据(刚访问的还要访问)具有频率局部性的数据(热门内容始终热门)
空间复杂度O(Capacity)O(\text{Capacity})O(Capacity)O(Capacity)O(\text{Capacity})O(Capacity),但常数略大
缺点容易被突发性的批量扫描(如数据备份)污染缓存新加入的元素频率低,容易被瞬间淘汰
http://www.jsqmd.com/news/466541/

相关文章:

  • PageHelper 解析及实现原理
  • 对比VBA学习Python,让办公更自动化!
  • 很多人卡在这一步:OpenClaw不会安装?这个一键版解决了
  • 【Linux】进程 PCB、task_struct、fork初识
  • 基于二进制的遗传算法的考虑排放目标和输电损耗的经济调度研究(Python代码实现)
  • 扫地机机器人研发岗深度解析与技术指南
  • 140个企业级实战场景剖析以及AI大模型项目实战
  • 函数式编程思想
  • 2026钻床市场热门:这些工厂钻床受追捧,目前优质的钻床品牌技术引领与行业解决方案解析 - 品牌推荐师
  • 汇源全屋定制作为全屋定制专业制造商,价格大概多少钱? - 工业推荐榜
  • 基于改进粒子群算法的含碳捕集微网多时间尺度低碳经济调度(Matlab代码实现)
  • Flutter 三方库 system_resources_2 的鸿蒙化适配指南 - 实时监控鸿蒙端侧 CPU 负载、内存占用与系统资源动态感知
  • 星焰家居这个不锈钢全屋定制厂商品牌靠不靠谱,值得推荐吗? - myqiye
  • 2026年热门的CNC 精密压铸加工公司推荐:医疗设备精密压铸加工/智能家居精密压铸加工采购指南厂家怎么选 - 行业平台推荐
  • # 发散创新:WebHID 在浏览器端实现外设通信的全新实践 在现代Web 开
  • 2026年评价高的储能弹簧工厂推荐:耐腐蚀弹簧/小家电电磁阀弹簧/高压直流继电器弹簧精选厂家推荐 - 行业平台推荐
  • Python开发英语记忆单词软件 - 优化
  • FFMpeg + WebSocket + JSMpeg 搭建低延迟视频系统(总览篇)
  • 2026年01月深圳CE:加速寿命试验/合规类/国内外认证/机构类/测试服务/温度老化试验/电子电气检测/腐蚀试验/选择指南 - 优质品牌商家
  • 2026国内小白纹绣培训重实操机构推荐榜:野生眉学校、零基础学纹眉、零基础小白、零基础纹眉学校、零结痂雾眉、韩式定妆学校选择指南 - 优质品牌商家
  • PAT 乙级 1078
  • 谁懂啊!OpenClaw(小龙虾)爆火不是没道理
  • Python基于flask的博客系统设计与实现
  • 总结AI蓝牙音箱生产厂,国内靠谱厂家Top10有哪些? - 工业品网
  • Flutter 三方库 shelf_cors_headers 的鸿蒙化适配指南 - 实现具备跨域安全访问策略的服务端拦截器、支持端侧微服务网关与分布式请求治理实战
  • 聊聊扬州月子中心按需定制,哪家品牌靠谱又有高性价比? - 工业设备
  • win11下解决eNSP AR启动40/41错误解决方案
  • Flutter 三方库 health_connector_core 的鸿蒙化适配指南 - 实现具备跨平台标准的数据采集与同步架构、支持端侧健康指标建模与设备总线协同实战
  • 牛客练习001:反转链表
  • 基于Matlab 2017a的单相交交变频电路仿真研究:阻感负载下的傅立叶分析与原理讲解