必须用双向链表+哈希表协同实现LRU缓存:双向链表支持O(1)移动/删除节点,哈希表提供O(1)查找与定位,二者结合满足LRU对时序维护和快速访问的双重需求。

用链表实现高性能 LRU 缓存,关键不是“只用链表”,而是用双向链表 + 哈希表协同工作。单靠链表无法满足 O(1) 查找要求,而只靠哈希表又无法维护访问时序——两者缺一不可。
为什么必须是双向链表,而不是单链表?
- 单链表删除中间节点时,需先遍历找到前驱节点(O(n)),而 LRU 中「访问命中后把节点移到头部」正是高频操作;
- 双向链表每个节点自带
prev和next指针,能直接定位前后节点,移动或删除任意节点都只需改几个指针(O(1)); - 尾部淘汰最久未使用项时,也只需取尾节点、断开连接、释放内存,无需遍历。
哈希表的作用是什么?
- 存储
key → 链表节点指针的映射; - 支持在 O(1) 时间内判断 key 是否存在、并直接定位到对应链表节点;
- 避免每次 get/put 都从头遍历链表找 key(否则退化为 O(n))。
核心操作怎么落地?
-
get(key):
- 哈希表查 key → 找不到返回 -1;
- 找到则从链表中摘下该节点,插入到头部(表示最近使用);
- 返回对应 value。
-
put(key, value):
- 哈希表查 key:
- 若存在 → 更新 value,并移到头部;
- 若不存在 → 新建节点插到头部;
- 插入后若 size > capacity → 删除尾节点,并从哈希表中移除对应 key。
- 哈希表查 key:
-
链表头部为“最新”,尾部为“最旧”:
- 通常设虚拟头尾哨兵节点(dummy head / tail),避免空链表边界判断,代码更简洁健壮。
实现细节建议
- 使用带哨兵的双向循环链表或双向非循环链表均可,但推荐非循环 + dummy head/tail;
- 哈希表可用标准库容器(如 C++
unordered_map、JavaHashMap、Pythondict),无需手写哈希; - 每次节点移动(如 moveToHead)应封装为独立函数,避免重复逻辑;
- put 时注意:更新已有 key 不增加 size,只有新增 key 才触发容量检查。
不复杂但容易忽略











