C++实现LRU缓存淘汰机制 _ 哈希表与双向链表结合【源码】

老伟大大_4085

老伟大大_4085

2026-04-12

504人浏览

原创

不能只用 std::unordered_map 实现 LRU,因其无法在 O(1) 内移动节点至表头以维护访问顺序;必须结合双向链表(如 std::list)并通过 splice 避免迭代器失效,配合哈希表实现 get/put 均为 O(1),且需校验 capacity 合法性。

c++实现lru缓存淘汰机制 _ 哈希表与双向链表结合【源码】

为什么不能只用 std::unordered_map 实现 LRU?

因为哈希表本身不记录访问顺序,std::unordered_map 查找是 O(1),但无法在常数时间内把某个 key “移到最近使用位置”。LRU 的核心操作——“访问即置顶”和“淘汰最久未用项”,必须支持快速定位 + 快速移动节点。单靠哈希表做不到,必须搭配能 O(1) 插入/删除任意节点的结构,双向链表正好满足。

std::list 能直接用吗?注意迭代器失效问题

可以,但要小心:每次 list::erase(iterator) 后,该迭代器立即失效;而如果你把 list::iterator 存在哈希表里(比如 unordered_map::iterator>),那每次从链表中移除节点后,对应 map 里的 iterator 就成了悬空指针——下次再解引用会崩溃。

实操建议:

  • 用 list::splice() 把节点从中间“剪切”并“粘贴”到头部,避免 erase + push_front,这样迭代器保持有效
  • 或者改用自定义双向链表(含 prev/next 指针),自己管理节点生命周期,更可控
  • 若坚持用 std::list,务必在每次 erase 后同步更新 map 中的 iterator,但逻辑易错,不推荐

如何让 get() 和 put() 都做到 O(1)?

关键在于哈希表与链表的双向绑定:

  • 哈希表存 key → node*(或 list::iterator),提供 O(1) 定位
  • 链表节点存 key 和 value,头部为最近使用,尾部为最久未用
  • get(key):查哈希表 → 找到节点 → 用 splice 移到链表头 → 返回 value
  • put(key, value):已存在则更新 value 并 splice 到头;不存在则新建节点插头,若超容,删尾节点并从哈希表 erase 对应 key

示例片段(简化):

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
auto it = cache_map.find(key);
if (it != cache_map.end()) {
    cache_list.splice(cache_list.begin(), cache_list, it->second); // O(1) 移动
    it->second->second = value; // 更新值
} else {
    cache_list.emplace_front(key, value);
    cache_map[key] = cache_list.begin();
    if (cache_list.size() > capacity) {
        auto& tail = cache_list.back();
        cache_map.erase(tail.first);
        cache_list.pop_back();
    }
}

容量为 0 或负数时怎么处理?

很多实现忽略这个边界,结果一设 capacity = 0 就无限插入、不淘汰,缓存失控。

正确做法:

  • 构造时对 capacity 做校验:if (capacity
  • 在 put() 中,先判断 capacity == 0:此时所有 put 都应等效于“清空旧值 + 不缓存新值”,即直接 erase 原 key(如有),且不插入新节点
  • 注意:capacity = 0 时 get() 仍应返回 -1(或默认值),但不触发任何链表操作

这个点容易被跳过,但线上环境一旦配置错误,会导致内存持续增长。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

2026.04.23

379

31

空指针异常处理
空指针异常处理

本专题整合了空指针异常解决方法,阅读专题下面的文章了解更多详细内容。

2025.11.16

179

10

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

2025.09.05

630

5

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.16

343

7

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

2025.11.17

533

20

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.27

303

6

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

2026.10.28

20

16

Vite 如何搭配 Vue.js
Vite 如何搭配 Vue.js

Vite搭配Vue.js专题汇集创建Vue 3项目、配置开发环境、路径别名、Vue插件、代理、多环境构建与调试的已审核文章,帮助读者完成从初始化到日常开发的配置。

2026.10.28

20

15

Vite 项目目录怎么看
Vite 项目目录怎么看

Vite项目目录专题汇集入口文件、src源码、public静态资源、路径别名、项目根目录和构建输出目录相关的已审核文章,帮助读者理解各文件夹的用途与引用方式。

2026.10.28

0

10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习