手写LRU缓存:3道高频面试题,打通底层逻辑
看了一堆教程还是不会写项目?别慌,这不是你的错。很多开发者卡在“懂原理”和“能落地”之间,面试时一提到 高频面试题 里的 LRU 缓存,脑子里全是概念,手却写不出代码。今天不讲虚的,直接拆解 LRU 缓存的核心考点,从算法原理到代码实现,帮你把这块硬骨头啃下来。
考点梳理:LRU 到底考什么?
面试官问 LRU(Least Recently Used,最近最少使用),通常不是只想听你背定义。他们想确认三件事:数据结构选型能力:你知道为什么需要结合哈希表和双向链表?
边界条件处理:容量满时怎么淘汰?键不存在时怎么处理?
性能意识:你能不能说出时间复杂度是 O(1),并解释为什么?很多初学者只记得“链表+哈希表”,但说不清为什么是双向链表而不是单向。这里有个关键细节:单向链表删除节点需要前驱节点,而双向链表可以直接通过节点指针访问前后节点,从而在 O(1) 时间内完成删除。这一点在面试中必须讲清楚,否则会被追问倒。
另外,NPM 官方包 lru-cache 是 JS 生态中实现 LRU 的经典库,其源码逻辑与本文讲解高度一致。研究官方实现,比看十篇博客更有效。你可以去 GitHub 上看 lru-cache 的源码,你会发现它正是用了 Map + 双向链表的变体实现。
标准答法:如何组织语言?
面试时,建议按“总-分-总”结构回答:
第一步:给出结论
“LRU 缓存通常用哈希表 + 双向链表实现,保证 get 和 put 操作都是 O(1) 时间复杂度。”
第二步:解释设计思路哈希表:键为缓存的 key,值为链表中对应节点的指针。用于 O(1) 查找。
双向链表:维护访问顺序。头部是最近使用的,尾部是最久未使用的。
操作逻辑:get(key):如果 key 存在,将对应节点移到头部,返回 value;否则返回 -1。
put(key, value):如果 key 存在,更新 value 并移到头部;如果不存在,新建节点插入头部,若超过容量,删除尾部节点,并同步删除哈希表中的键。第三步:强调优势
“相比数组或普通链表,这种结构避免了 O(n) 的查找或插入开销,特别适合缓存场景。”
注意:不要只说“用哈希表和链表”,必须点明是双向链表,并说明理由。这是区分“背答案”和“真理解”的关键。
代码实现:Python 逐行讲解
下面用 Python 实现一个标准的 LRU 缓存,代码简洁,注释清晰,适合面试手写。
class Node:def __init__(self, key=0, value=0):self.key = keyself.value = valueself.prev = Noneself.next = Noneclass LRUCache:def __init__(self, capacity: int):self.capacity = capacityself.cache = {} # key - Node# 双向链表哨兵节点,避免边界判断self.head = Node()self.tail = Node()self.head.next = self.tailself.tail.prev = self.headdef _remove_node(self, node: Node):从链表中移除节点node.prev.next = node.nextnode.next.prev = node.prevdef _add_to_head(self, node: Node):将节点添加到头部(最近使用)node.next = self.head.nextnode.prev = self.headself.head.next.prev = nodeself.head.next = nodedef get(self, key: int) - int:if key not in self.cache:return -1node = self.cache[key]# 移动到头部,表示最近使用self._remove_node(node)self._add_to_head(node)return node.valuedef put(self, key: int, value: int) - None:if key in self.cache:# 更新值,并移动到头部node = self.cache[key]node.value = valueself._remove_node(node)self._add_to_head(node)else:# 新建节点new_node = Node(key, value)self.cache[key] = new_nodeself._add_to_head(new_node)# 超过容量,淘汰尾部节点if len(self.cache) self.capacity:lru_node = self.tail.prevself._remove_node(lru_node)del self.cache[lru_node.key]逐行解析关键点:哨兵节点(head/tail):避免处理空链表或头尾节点的边界情况,代码更简洁。
_remove_node 和 _add_to_head:封装链表操作,逻辑清晰,便于复用。
put 中的淘汰逻辑:注意先添加新节点,再判断容量,这样保证新节点不会立即被淘汰。
哈希表同步删除:删除尾部节点时,必须同时删除哈希表中对应的键,否则会导致内存泄漏或数据不一致。这段代码在 PyPI 官方包 中虽无直接对应,但逻辑与 functools.lru_cache 装饰器底层实现思路一致。lru_cache 内部也使用了类似的双向链表结构来管理缓存条目。
追问与延伸:面试官还会问什么?
追问1:为什么不用单向链表?
答:单向链表删除节点需要 O(n) 时间找前驱,而双向链表可以 O(1) 删除。在缓存高频读写场景下,性能差异显著。
追问2:如果并发访问,怎么改造?
答:可以加锁,但会降低性能。更优方案是使用线程本地缓存,或采用分段锁。在分布式场景下,可以考虑 Redis 的 LRU 策略,它基于近似算法,适合大规模数据。
追问3:LRU 和 LFU 有什么区别?
答:LRU 淘汰最久未使用的,LFU 淘汰最少使用的。LFU 需要额外记录访问频率,实现更复杂,但适合访问模式不随时间变化的场景。
避坑提醒:手写代码时,不要漏掉哈希表的同步删除,这是最常见的 bug。
测试用例要覆盖:容量为 1、重复 put 相同 key、get 不存在的 key 等边界情况。记忆口诀:快速回忆核心逻辑
为了方便面试前快速回顾,送你一个口诀:哈希查节点,链表管顺序;
Get 移头部,Put 先判断;
存在则更新,不存在则新;
超容删尾部,哈希同步删。这四句话涵盖了 LRU 缓存的所有核心操作。面试时,先背口诀,再展开细节,能极大提升表达流畅度。
总结与行动建议
LRU 缓存是 高频面试题 中的经典,但绝非难到无法攻克。关键在于理解“哈希表 + 双向链表”的设计动机,并能手写代码。建议你:亲手敲一遍上面的 Python 代码,不要只看不练。
用测试用例验证,包括边界情况。
对比 NPM/PyPI 官方包的实现,理解工程化细节。这个知识点你面试被问过吗?留言说说,你当时是怎么回答的?有没有被追问到哑口无言?
企业数字化 ERP 产品动态
相关推荐
3个步骤搞定红楼梦人物分析,面试必问不踩坑 3个步骤搞定红楼梦人物分析,面试必问不踩坑 版本升级后 API 全变了,你还在死记硬背?别慌。 这是大厂面试里的高频坑,也是【红楼梦人物分析】这类文本处理题的核心考点。很多转岗开发者栽在这里,以为只是简单的字符串匹配,结果一上手发现数据结构… · 2026/9/23 15:19:08
DeepSeek本地部署实战:从Ollama到vLLM的推理框架与开发工具链接入指南 简介:这份DeepSeek入门与应用指南,面向对AI、NLP和推理模型感兴趣的研发工程师与技术爱好者,系统讲解开源推理模型DeepSeek-R1的核心能力、技术定位与实际应用场景。资源包含1个PDF文档,压缩包大小4.83MB,内容按“是什… · 2026/9/23 15:19:02
STM32F103C8T6最小系统硬件设计五重校验指南 简介:本资源是一份面向STM32初学者与嵌入式开发入门者的硬件设计参考材料,聚焦STM32F103C8T6最小系统的核心电路原理与引脚功能解析,解决新手搭建可靠开发板时常见的电源设计、复位异常、时钟失效、烧录失败等关键问题。压缩包为单个PDF文件&… · 2026/9/23 15:18:55
dldl1面试避坑指南:搞定原理与性能优化 dldl1面试避坑指南:搞定原理与性能优化 面试现场,被问“dldl1底层原理”时脑子一片空白?这不仅是你的痛点,更是90%开发者的软肋。很多老手在谈 性能优化… · 2026/9/23 15:55:24
Sobol全局灵敏度分析实战:从采样到参数标定的工程闭环 简介:本资源是一份面向科研人员、工程建模者及高年级本科生的Sobol全局灵敏性分析原理与实操指南,聚焦解决多输入复杂系统中参数重要性识别与不确定性量化难题。PDF文档系统阐述了基于方差分解的Sobol方法理论框架,涵盖参数范围设定、Sobol序… · 2026/9/23 15:55:24
4个步骤搞定读书日项目:给建筑工人的移动端开发保姆级教程 4个步骤搞定读书日项目:给建筑工人的移动端开发保姆级教程 刚学会Python语法,面对空白编辑器发呆?别慌,这是90%新手的通病。很多在职建筑工人想转行或搞副业,卡在“会写代码但不会搭项目”这一步。… · 2026/9/23 15:55:24
从递归本质到B+树:彻底弄懂数据结构的树 学数据结构的人,十有八九会在“树”这一章栽跟头。我当年复习数据结构,前面线性表、栈和队列还能靠死记硬背蒙混过关,一到树这里,整个人都是懵的——满二叉树、完全二叉树、平衡二叉树、哈夫曼树、红黑树、B树、字典树……名字堆在… · 2026/9/23 15:55:17
联邦学习在NSL-KDD网络入侵检测中的工程落地实践 简介:本资源是一套基于Python实现的联邦学习网络入侵检测完整项目,面向网络安全与机器学习方向的学习者、高校课程实践者及科研入门者,聚焦NSL-KDD数据集上的分布式建模与异常流量识别问题,适用于隐私敏感场景下的协同安全分析教学… · 2026/9/23 15:55:17
中职组网络安全赛项实战:渗透测试、安全加固与数字取证流量分析 简介:这份资源是2022年全国职业院校技能大赛中职组网络安全赛项的完整赛题文档,面向职业院校网络安全竞赛选手、指导教师以及备考相关技能认证的学习者,帮助其熟悉正式赛题的题型结构、任务要求与评分标准。压缩包内仅含1个docx文件ÿ… · 2026/9/23 15:55:04
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29