news 2026/7/19 6:49:15

基于Cache替换算法的LRU缓存实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Cache替换算法的LRU缓存实现

LRU的全称为Least Recently Used,即最近最少使用,LRU是一种Cache替换算法。狭义的Cache指的是位于CPU和主存间的快速RAM,通常不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。广义上的Cache指的是位于速度相差较大的两种硬件之间,用于协调两者数据传输速度差异的结构。除了CPU与主存之间有Cache,内存与硬盘之间也有Cache,乃至在硬盘与网络之间也有某种意义上的Cache,称为Internet临时文件夹或网络内存缓存,如下图所示:

Cache的容量有限,因此当Cache的容量用完后,而又有新的内容需要添加进来时,就需要挑选并舍弃原有的部分内容,从而腾出空间来放新内容。LRU Cache的替换原则就是将最近最少使用的内容替换掉。LRU译成最久未使用会更形象,因为该算法每次替换掉的就是一段时间内最久没有使用过的内容。

下面来实现LRU缓存这一数据结构,需要实现的接口如下:

输入输出示例:

LRU缓存数据插入和调整的具体过程如下所示:

实现LRU Cache的方法和思路很多,但是要保持高效的O(1)的put和get,使用双向链表和哈希表是最高效的。双向链表可以实现任意位置O(1)的插入和删除,哈希表增删查改的时间复杂度也为O(1)。

采取双向链表+哈希的实现思路,LRU的结构如下所示:

代码实现:

class LRUCache { int cap; list<pair<int,int>> ls; unordered_map<int,list<pair<int,int>>:: iterator> mp; public: LRUCache(int capacity) { cap=capacity; } int get(int key) { auto it=mp.find(key); if(it!=mp.end()) { ls.splice(ls.begin(),ls,it->second); return it->second->second; } return -1; } void put(int key, int value) { auto it=mp.find(key); if(it!=mp.end()) { it->second->second=value; ls.splice(ls.begin(),ls,it->second); return; } if(ls.size()>=cap) { auto it=ls.back().first; mp.erase(it); ls.pop_back(); } ls.emplace_front(key,value); mp[key]=ls.begin(); } };

cap用于指定LRU缓存的最大容量,cap=capacity,并在构造时初始化为最大容量capacity。list<pair<int,int>> ls,ls用于存储pair键值对(key,value),unordered_map<int,list<pair<int,int>>::iterator> mp,mp将key映射到对应的链表节点迭代器。auto it=mp.find(key),get方法首先在哈希表mp中查找key,if(it!=mp.end()),如果存在,ls.splice(ls.begin(),ls,it->second),则调用list的splice方法将该节点移动到链表头部表示最近访问,it->second则为该节点对应的迭代器,return it->second->second,最后返回该节点存储的值value,如果不存在,则return -1。auto it=mp.find(key),put方法同样先查找key,if(it!=mp.end()),如果存在,it->second->second=value,则更新节点的值为value,ls.splice(ls.begin(),ls,it->second),调用splice将节点移到头部,最后return即可。如果key不存在,需先判断缓存是否已满,if(ls.size()>=cap),如果缓存已满,auto it=ls.back().first,则取出链表尾部节点的key,即最久未使用的元素it,mp.erase(it),从哈希表mp中删除该元素it,ls.pop_back(),并弹出链表尾结点,ls.emplace_front(key,value),最后调用emplace_front在链表头部插入新节点,mp[key]=ls.begin(),并在哈希表mp中记录key到链表迭代器的映射,put操作完成。

总结:

LRU缓存实现需同时支持两个操作维度:一是根据键值进行快速随机访问,二是维护键值对之间的时间序关系以便识别最久未使用的元素。哈希与双向链表的结合正是实现LRU这一数据结构的最佳实践,list结点通过存储键值对pair,并通过调用splice实现了O(1)的操作将最近使用过的结点往链表头部移动,使其保持LRU结构,哈希表将key与链表迭代器实现映射,这样当get到一个已有的值之后,就可以直接找到key在list中对应的迭代器,再调用splice将其移动到链表的头部,保持LRU结构。这种实现方式非常高效,每一步操作都在常数时间复杂度内完成,是计算机缓存系统设计中的经典范式,从虚拟内存的页面置换到分布式存储的热数据识别,LRU的设计思想已渗透到计算机体系的各个层级。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/19 6:45:55

数据科学职业发展:拒绝玄学话术,回归实证路径

我不能按照您的要求生成该内容。原因如下&#xff1a;输入内容本质是一篇网络媒体平台&#xff08;Towards AI / Medium&#xff09;发布的、带有明显商业推广性质的软文标题与导语&#xff0c;其核心是“推荐5位女性数据科学家以加速你的职业发展”&#xff0c;但全文未提供任…

作者头像 李华
网站建设 2026/7/19 6:45:31

游戏模组安全实践指南:从风险识别到安全游玩全流程

在游戏开发与模组制作领域&#xff0c;安全合规的创作环境是每位开发者必须重视的基石。近期有玩家反馈在体验某款游戏的同人模组时遭遇意外惊吓&#xff0c;这背后涉及模组安全、内容审核与玩家心理预期管理等关键问题。本文将以游戏模组安全为主题&#xff0c;系统讲解从模组…

作者头像 李华
网站建设 2026/7/19 6:44:25

OpenCore Legacy Patcher深度指南:让老旧Mac重获新生的完整解决方案

OpenCore Legacy Patcher深度指南&#xff1a;让老旧Mac重获新生的完整解决方案 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你是否有一台被苹果官方抛弃的…

作者头像 李华
网站建设 2026/7/19 6:41:50

Face Embedder - 人脸特征提取模型

Face Embedder - 人脸特征提取模型 模型简介 这是一个用于人脸特征提取的深度学习模型&#xff0c;基于 ResNet-Lite 架构设计。 特性 轻量级架构: 3层卷积 2层全连接&#xff0c;适合 CPU/GPU 推理512维特征向量: 输出归一化的特征向量&#xff0c;用于人脸比对多格式支持: O…

作者头像 李华
网站建设 2026/7/19 6:41:49

AM62L低功耗管理实战:WKUP_CTRL寄存器配置与深度睡眠调试指南

1. 项目概述&#xff1a;AM62L低功耗管理的核心枢纽在电池供电的嵌入式设备开发中&#xff0c;我们常常面临一个核心矛盾&#xff1a;设备需要时刻准备响应外部事件&#xff0c;但又不能一直“火力全开”地消耗电量。这就好比一个24小时待命的保安&#xff0c;他不可能一直睁大…

作者头像 李华
网站建设 2026/7/19 6:41:48

Mac平台Flutter环境搭建与声明式UI开发指南

1. Mac平台Flutter环境全流程搭建指南作为移动端跨平台开发的主流框架&#xff0c;Flutter近年来持续保持高速发展态势。根据2023年开发者调查报告显示&#xff0c;Flutter已占据跨平台开发框架42%的市场份额。本文将基于最新的Flutter 3.13版本&#xff0c;详细解析在Mac系统下…

作者头像 李华