跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端算法

LRU 缓存机制设计与 JavaScript 实现

LRU 缓存机制通过哈希表与双向链表结合实现 O(1) 时间复杂度的读写操作。哈希表用于快速定位节点,双向链表维护访问顺序,头部为最新数据,尾部为最旧数据。当容量满时淘汰尾部节点。实现包含虚拟头尾节点简化边界处理,核心步骤包括获取节点后移至头部、插入新节点至头部及容量溢出时的尾部淘汰逻辑。该方案广泛应用于系统缓存设计中。

极客零度发布于 2026/3/16更新于 2026/10/2092 浏览
LRU 缓存机制设计与 JavaScript 实现

场景想象:

你有一个书架(缓存),容量有限(比如只能放 3 本书)。

规则是'最近最少使用 (Least Recently Used)'淘汰:

  1. 读取:如果你读了一本书,它就变得'新鲜'了,要把它抽出来放到最前面。
  2. 插入:
    • 如果书架没满,新书直接插到最前面。
    • 如果书架满了,必须把最后面那本(最久没人看的那本)扔掉,然后把新书插到最前面。

技术难点:

我们需要两个操作:get(查找)和 put(插入/更新)。

题目要求这两个操作的时间复杂度必须都是 $O(1)$。

  • 只用数组? 插入/删除慢($O(N)$)。
  • 只用链表? 查找慢($O(N)$)。
  • 只用对象/Map? 没办法维护'谁是最新的、谁是最旧的'这种顺序。

终极方案:哈希表 + 双向链表

  • 哈希表 (Map):负责 $O(1)$ 找到某个节点。
  • 双向链表 (Double Linked List):负责 $O(1)$ 移动节点位置(因为双向链表删除节点不需要遍历找前驱)。
力扣 146. LRU 缓存

https://leetcode.cn/problems/lru-cache/

文章配图

题目分析:

  • 输入:capacity (容量)。
  • 实现:
    • get(key): 如果存在,返回 value,并把它移到最新位置;不存在返回 -1。
    • put(key, value): 如果 key 存在,更新 value 并移到最新;如果不存在,插入新节点(可能需要淘汰最老的)。
核心思维:虚拟头尾 + Map 映射

为了操作方便,我们给双向链表加上 Dummy Head 和 Dummy Tail。

  • Head 右边:永远是最新的数据。
  • Tail 左边:永远是最旧的数据(淘汰候补)。
代码实现 (JavaScript)

这是一道工程题,代码量稍大,但逻辑非常模块化。

// 1. 定义双向链表节点
class Node {
  constructor(key, value) {
    . = key;
    . = value;
    . = ;
    . = ;
  }
}


  {
  
  () {
    . = capacity;
    . =  (); 
    
    
    . =  (, );
    . =  (, );
    
    
    .. = .;
    .. = .;
    
    
    . = ;
  }

  
  () {
     (!..(key)) {
       -;
    }
    
     node = ..(key);
    
    .(node);
     node.;
  }

  
  () {
     (..(key)) {
      
       node = ..(key);
      node. = value;
      .(node);
    }  {
      
       newNode =  (key, value);
      ..(key, newNode);
      .(newNode); 
      .++;
      
      
       (. > .) {
        
         removedNode = .();
        ..(removedNode.); 
        .--;
      }
    }
  }

  
  
  
  () {
    node. = .;
    node. = ..;
    ... = node;
    .. = node;
  }

  
  () {
    node.. = node.;
    node.. = node.;
  }

  
  () {
    .(node); 
    .(node);  
  }

  
  () {
    
     node = ..;
    .(node);
     node; 
  }
}
this
key
this
value
this
prev
null
this
next
null
// 2. LRU 缓存类
class
LRUCache
/** * @param {number} capacity */
constructor
capacity
this
capacity
this
map
new
Map
// key -> Node
// 创建虚拟头尾节点
this
head
new
Node
0
0
this
tail
new
Node
0
0
// 连起来:head <-> tail
this
head
next
this
tail
this
tail
prev
this
head
// 当前节点数量
this
size
0
/** * @param {number} key * @return {number} */
get
key
if
this
map
has
return
1
// 取出节点
const
this
map
get
// 【关键】既然读了它,它就变'新'了,必须移动到链表头部
this
moveToHead
return
value
/** * @param {number} key * @param {number} value * @return {void} */
put
key, value
if
this
map
has
// 情况 1:key 已存在,修改值,并移到头部
const
this
map
get
value
this
moveToHead
else
// 情况 2:key 不存在,新建节点
const
new
Node
this
map
set
this
addToHead
// 放到头部
this
size
// 检查是否超容
if
this
size
this
capacity
// 淘汰最久未使用的(也就是 tail 前面那个)
const
this
removeTail
this
map
delete
key
// 别忘了从 Map 里也删掉
this
size
// --- 内部辅助函数 (这就是链表操作的基本功) ---
// 1. 将节点添加到头部 (head 之后)
addToHead
node
prev
this
head
next
this
head
next
this
head
next
prev
this
head
next
// 2. 删除一个节点 (双向链表删除 O(1))
removeNode
node
prev
next
next
next
prev
prev
// 3. 把一个已有节点移到头部
moveToHead
node
this
removeNode
// 先从原来的位置断开
this
addToHead
// 再插到头部
// 4. 移除尾部节点 (用于淘汰)
removeTail
// tail.prev 才是真正的最后一个有效节点
const
this
tail
prev
this
removeNode
return
// 返回被删的节点,因为外层还需要它的 key 来删 Map
深度模拟

假设 capacity = 2。

  1. put(1, 1): Map {1: Node(1)}. List: Head <-> 1 <-> Tail.
  2. put(2, 2): Map {1: Node(1), 2: Node(2)}. List: Head <-> 2 <-> 1 <-> Tail. (2 最新)
  3. get(1): 读了 1。1 变新了,移到头。
    • List: Head <-> 1 <-> 2 <-> Tail.
  4. put(3, 3): 满员了!需要淘汰。
    • 淘汰谁?Tail 前面的那个,也就是 2。
    • Map 删除 2。
    • 插入 3。List: Head <-> 3 <-> 1 <-> Tail.
  5. get(2): 此时 Map 里没有 2 了,返回 -1。

目录

  1. 力扣 146. LRU 缓存
  2. 核心思维:虚拟头尾 + Map 映射
  3. 代码实现 (JavaScript)
  4. 深度模拟

更多推荐文章

查看全部
  • OpenClaw 对接 QQ 机器人实战指南:本地与云端部署方案
  • VRM4U 插件完整指南:在 Unreal Engine 5 中高效处理 VRM 模型
  • 2026年写论文最好用的AI模型TOP榜出炉!究竟哪家能拔得
  • SkyWalking Python 应用追踪:基于 skywalking-python 的埋点实战
  • 前端 TypeScript 高级技巧:构建更安全的代码
  • FPGA 入门实战:利用 LED 实现 2 选 1 多路选择器
  • AI 绘画报错:CheckpointLoaderSimple 模型加载失败修复
  • OpenClaw 实战指南:从零搭建本地 AI 自动化助手
  • 绿联 NAS 配置 WebDAV 公网访问并使用 RaiDrive 挂载
  • C++ list 模拟实现:带头双向链表增删查改详解
  • Lottie-Web 动画开发技术指南
  • 2024 生成式人工智能指南:大模型行业应用与开发实战
  • Python 属性描述符:原理与 ORM 应用
  • RAG 系统链路解析与 Document Loaders 多案例实战
  • OpenClaw 接入自定义模型并通过 WebUI 实现智能操作
  • 飞书机器人图片消息发送流程及常见问题解决
  • 程序员如何入局 AI 大模型及职业发展路径
  • 基于 Higress 将 REST API 转换为 MCP Server 工具
  • Python 打造 AI 三剑客:文档总结、代码生成与资料检索
  • Python pytesseract 库:图像文字识别原理与实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online