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

LRU(Least Recently Used)原理及算法实现

1.前言        

        LRU(Least Recently Used,最近最少使用) 是一种经典的 缓存淘汰算法,用于在缓存空间不足时决定哪些数据应被移除。其核心思想是:优先淘汰最长时间未被访问的数据,保留最近被访问的数据。

        这里制定的规则是最近最少使用,如果等效为优先级最高,那么其实和RTOS任务切换的最高优先级任务选择的场景是几乎相同的。当然,RTOS中使用了双向链表维护就绪态任务列表数组,并按优先级进行了排序。

2.实现方式   

        LRU 缓存的核心规则是:
①当访问(get)或插入(put)数据时,将该数据标记为 “最近使用”。
②当缓存满时,新插入数据会淘汰 “最久未被使用” 的数据。

        要实现这一规则,需要高效支持两个操作:
①快速查找数据(判断是否存在)。
②快速移动或删除数据(更新 “最近使用” 状态)。

1. 双向链表 + 哈希表(O(1)复杂度)

         如上图所示,通过哈希映射来快速定位节点位置,双向链表用于维护节点信息,越接近链表尾部的节点最近使用最少。相关实现涉及的操作如下:

  • 访问数据:将节点移到链表头部;

  • 淘汰数据:删除链表尾部节点;

  • 新增数据:插入链表头部;

2. 代码实现

class LRUCache 
{
private:list<pair<int, int>> cache; // 双向链表:key-valueunordered_map<int, list<pair<int, int>>::iterator> map; // key->链表节点指针int capacity;  //缓存的最大容量,超过此容量时需要淘汰数据。public:LRUCache(int cap) : capacity(cap) {}//根据key查找缓存中的值,若存在则返回值,并将该数据标记为 “最近使用”;若不存在则返回-1。int get(int key){if(map.find(key) == map.end()) {            return -1;  //若不存在,返回-1。}         cache.splice(cache.begin(), cache, map[key]);   //移至链表头部(标记最近使用)       return map[key]->second;     //返回该节点的value}//插入新的key-value,或更新已有key的值,并将其标记为 “最近使用”;若缓存满,则淘汰最久未使用的数据。void put(int key, int value) {        if(map.find(key) != map.end())  //若key已存在{            map[key]->second = value;   //更新值            cache.splice(cache.begin(), cache, map[key]);   //用splice将节点移到链表头部return;}if(cache.size() == capacity) // 缓存满,淘汰尾部{auto last = cache.back();map.erase(last.first); // 从哈希表删除该节点的keycache.pop_back();     // 从链表删除尾部节点}// 新数据插入头部cache.emplace_front(key, value);map[key] = cache.begin();}
};
变量类型作用
cachelist<pair<int, int>>双向链表,存储key-value键值对。链表头部是 “最近使用” 的数据,尾部是 “最久未使用” 的数据。
mapunordered_map<int, list::iterator>哈希表,键为key,值为链表中对应节点的迭代器(指针)。用于快速定位链表中的节点,避免遍历链表。
capacityint缓存的最大容量,超过此容量时需要淘汰数据。

 3.汽车 ADAS 系统的传感器缓存

        在资源有限的嵌入式系统中,优先保留最近使用的传感器数据(如刹车温度),可快速响应紧急事件。

#define CACHE_SIZE 10
typedef struct {int sensor_id;float data;uint32_t last_access;bool valid;  // 增加有效性标志位
} SensorCache;SensorCache cache[CACHE_SIZE] = {0}; // 初始化全为invalid// 时间戳获取函数(1us分辨率)
uint32_t get_timestamp() 
{return DWT->CYCCNT / (SystemCoreClock / 1000000); 
}void update_cache(int id, float value) 
{int empty_slot = -1;       // 记录可用空槽int lru_index = -1;        // 真实LRU槽位uint32_t oldest = 0xFFFFFFFF;// 第一遍扫描:查找匹配和空槽for(int i=0; i<CACHE_SIZE; i++) {// 情况1:找到匹配传感器if(cache[i].valid && cache[i].sensor_id == id) {cache[i].data = value;cache[i].last_access = get_timestamp();return; // 直接返回}// 情况2:记录空槽位置if(!cache[i].valid) {empty_slot = i; // 不break,继续找可能的匹配项}}// 第二遍扫描:仅当无空槽时寻找真实LRUif(empty_slot == -1) {for(int i=0; i<CACHE_SIZE; i++) {if(cache[i].valid && cache[i].last_access < oldest) {oldest = cache[i].last_access;lru_index = i;}}} else {lru_index = empty_slot; // 优先使用空槽}// 更新缓存cache[lru_index].sensor_id = id;cache[lru_index].data = value;cache[lru_index].last_access = get_timestamp();cache[lru_index].valid = true; // 标记有效
}

http://www.dtcms.com/a/304821.html

相关文章:

  • Qt 移动应用发布与分发指南
  • Stable Diffusion推导与理解:从文本到图像的生成革命
  • 不用编程序无需联外网,将罗克韦尔(AB)PLC的标签数据存入SQL数据库
  • 以需求破局:DPVR AI Glasses 重塑 AI 眼镜产业生态
  • Apache Ignite 关于 **Executor Service(执行器服务)** 的介绍
  • Zynq SOC FPGA嵌入式裸机设计和开发教程自学笔记:GPIO扩展与中断控制技术,万字详解!!
  • 墨者:SQL注入下的文章汇总
  • AUTOSAR进阶图解==>AUTOSAR_SRS_LIN
  • 【LoRA微调】采用Lora微调时,假设设置的rank值为8,那么在微调时只会调整秩在8以下的矩阵还是只会调整秩等于8的矩阵
  • C++基础:模拟实现queue和stack。底层:适配器
  • openbmc 阈值sensor分析
  • 第二课 P-MOS管应用
  • 洛谷 P11227 [CSP-J 2024] 扑克牌
  • 微算法科技(NASDAQ:MLGO)应用区块链联邦学习(BlockFL)架构,实现数据的安全传输
  • Ika Network 正式发布,让 Sui 智能合约可管理跨链资产
  • 格雷码的应用场景
  • 光环云在2025WAIC联合发布“AI for SME 全球普惠发展倡议”
  • 银行回单识别和发票识别相结合的应用场景及技术方案
  • 20250729-day23
  • 【Mac版】Linux 入门命令行快捷键+联想记忆
  • RDD的checkpoint检查点机制(Checkpoint 与 Persist 的区别)
  • 负载均衡、算法/策略
  • linux实战--日志管理
  • 数字ic后端设计从入门到精通13(含fusion compiler, tcl教学)全定制版图设计
  • 【嵌入式电机控制#17】电流环(四):电流闭环控制
  • 汽车品牌如何用直播“开出去”?从展厅到售后,一站式解决方案
  • 智慧园区系统引领未来:一场科技与生活的完美融合
  • 微信小程序无法构建npm,可能是如下几个原因
  • linux内核报错汇编分析
  • C++学习之继承