c++如何实现LRU缓存算法_c++ LRU设计与实现【源码】
发布时间 - 2026-02-01 00:00:00 点击率:次用std::list+std::unordered_map实现O(1)LRU缓存的关键是:用map映射key到list迭代器,通过splice快速移动节点至头部,淘汰时取back()并同步更新map;需注意splice参数合法性、迭代器有效性、put时的更新/插入逻辑顺序及线程安全限制。
用 std::list + std::unordered_map 实现 O(1) LRU
LRU 缓存的核心难点是「快速定位最久未用项」和「频繁移动访问项到最近位置」,C++ 标准库里没有现成的双向链表+哈希混合结构,但可以用 std::list 存节点顺序、std::unordered_map 做键到链表迭代器的映射,两者配合达成插入、查询、更新全 O(1)。
关键点在于:不能把值直接存在 std::list 里再靠遍历找——那会退化成 O(n);必须让 map 的 value 是 std::list,这样通过 key 一查就知道它在链表哪,splice 一下就能移到头部。
-
std::list用push_front插新项,用splice把已有节点提到头部(不是 erase + push,避免重复构造) -
std::unordered_map的 key 是缓存 key,value 是对应std::list<:pair v>>::iterator - 淘汰时直接取
list.back(),然后从 map 中 erase 对应 key
注意 std::list::splice 的参数陷阱
很多人写 cache.splice(cache.begin(), cache, it) 想把 it 移到开头,结果运行时报错或行为异常——这是因为 splice 要求两个 list 是同一个对象,而传入的 it 必须属于当前 list。更隐蔽的问题是:如果用 it 之后又用了 map 的迭代器(比如 erase),it 可能失效(虽然 std::list 迭代器不因插入/删除失效,但 erase map 后若误用旧 it 就危险)。
- 安全写法:先
auto it_list = map.at(key)拿到链表迭代器,再cache.splice(cache.begin(), cache, it_list) - 不要在
splice后继续用原it_list做其他操作,除非确认没被 invalidate(其实一般不会,但逻辑上建议用完即弃) - 如果用 C++11 之前的编译器,
splice不支持三参数形式,得用四参数:cache.splice(cache.begin(), cache, it_list, std::next(it_list))
构造函数和容量控制要提前处理 key 冲突
LRU 缓存初始化时指定容量 capacity,但很多人忽略:当 put(k, v) 时,如果 k 已存在,应该更新值并提升优先级,而不是当成新 key 处理;如果不存在且缓存已满,才淘汰尾部再插入。这个判断顺序错了就会导致容量失控或重复插入。
- 每次
put先查map.find(key) != map.end():存在则splice+ 更新 value;不存在再看 size 是否已达capacit
y
- 淘汰前务必先
map.erase(list.back().first),再list.pop_back(),顺序反了会导致 dangling iterator - 别在构造函数里预分配 list 节点——LRU 是按需增长的,预填会干扰访问序
线程安全不是默认选项,别想当然加锁
标准 std::list 和 std::unordered_map 都不保证并发读写安全。如果你的 LRU 会被多线程调用,不能只给成员函数加 std::mutex 就完事——比如 get 中查 map、取迭代器、访问 list 三个动作必须原子,否则可能拿到迭代器后 list 被别的线程 splice 走,导致解引用崩溃。
- 最简方案:整个操作用一个
mutable std::mutex mtx包住,所有 public 方法加std::lock_guard - 高并发场景慎用:锁粒度太大,
get和put会互相阻塞,此时考虑用分段锁或无锁结构(如基于 hazard pointer 的实现),但复杂度陡增 - 别依赖
std::shared_mutex做读写锁优化——因为get实际上也要写(要splice),所以读多写少的优势基本不存在
真正难的不是写对单线程版,而是想清楚哪些操作必须串行、哪些可以分离。比如 key 查找和 value 构造可以挪到锁外,但链表结构调整和 map 更新必须一起锁住。
# ai
# c++
# 无锁
# 标准库
# red
# 成员函数
# 构造函数
# auto
# mutable
# public
# 线程
# 多线程
# pointer
# map
# 并发
# 对象
# 算法
# 迭代
# 链表
# 不存在
# 很多人
# 移到
# 就会
# 都不
# 就能
# 已有
# 可以用
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Microsoft Edge如何解决网页加载问题 Edge浏览器加载问题修复
Laravel如何处理和验证JSON类型的数据库字段
如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环
html5如何设置样式_HTML5样式设置方法与CSS应用技巧【教程】
如何在阿里云购买域名并搭建网站?
JavaScript实现Fly Bird小游戏
Laravel策略(Policy)如何控制权限_Laravel Gates与Policies实现用户授权
Laravel如何使用Sanctum进行API认证?(SPA实战)
如何基于云服务器快速搭建个人网站?
如何确认建站备案号应放置的具体位置?
如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)
如何在阿里云高效完成企业建站全流程?
html如何与html链接_实现多个HTML页面互相链接【互相】
ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法
Laravel如何实现一对一模型关联?(Eloquent示例)
Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践
香港服务器如何优化才能显著提升网站加载速度?
bootstrap日历插件datetimepicker使用方法
高性能网站服务器部署指南:稳定运行与安全配置优化方案
深圳防火门网站制作公司,深圳中天明防火门怎么编码?
如何在服务器上三步完成建站并提升流量?
怎么用AI帮你设计一套个性化的手机App图标?
Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践
手机怎么制作网站教程步骤,手机怎么做自己的网页链接?
如何在景安服务器上快速搭建个人网站?
jQuery 常见小例汇总
Python制作简易注册登录系统
如何快速生成橙子建站落地页链接?
高性价比服务器租赁——企业级配置与24小时运维服务
深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?
Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理
Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】
极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?
Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧
Laravel如何实现数据库事务?(DB Facade示例)
Laravel如何使用.env文件管理环境变量?(最佳实践)
Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】
如何在阿里云虚拟主机上快速搭建个人网站?
php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】
网站制作价目表怎么做,珍爱网婚介费用多少?
Laravel如何自定义分页视图?(Pagination示例)
5种Android数据存储方式汇总
Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives
Laravel怎么定时执行任务_Laravel任务调度器Schedule配置与Cron设置【教程】
香港服务器部署网站为何提示未备案?
Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】
Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧
Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
桂林网站制作公司有哪些,桂林马拉松怎么报名?


