LRU缓存机制(链表实现)

简介: LRU缓存机制(链表实现)

题目描述

image.png

解题思路

  1. 构造一个链表节点类和一个LRU缓存类。
  2. 一个链表的节点应该具有key,value,和next指针和prev指针。
  3. 一个LRU的实例应该具有容量capacity,hash对象,表示这个LRU中节点的数量值的count,两个辅助链表节点,分别指向最近使用的元素,和最久未使用的元素。
  4. get方法:无论是get方法还是put方法,都要首先取出key对应的节点,判断这个节点是否是undefined,如果不存在,直接返回-1,如果存在,将其从链表中删除,然后添加到辅助链表Head的指向位置,然后返回该节点的值。
  5. put方法:首先取出key对应的节点,判断这个节点是否是undefined,如果不是undefiend,更新其值,然后从链表中删除,然后添加到辅助头节点指向的位置,如果不存在,首先判断LRU中节点的数量和容量是否相等,如果相等,则说明已经满了,此时从尾部辅助链表前取出该元素,然后删除链表中的该元素,然后从hash对象中也删除,同时count--,然后创造一个新节点,存入key,value,然后添加到链表和hash对象中,同时更新count的值。

AC代码

// 首先构造一个链表节点类
class ListNode {
  constructor(key,value) {
    this.key = key;
    this.value = value;
    this.next = null;
    this.prev = null;
  }
}
// 构造一个LRU缓存类
class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.hash = {};
    this.count = 0;
    // 这里的head可以理解为最近使用过的,tail则可以理解为最久未使用的
    this.dummyHead = new ListNode();
    this.dummyTail = new ListNode();
    this.dummyHead.next = this.dummyTail;
    this.dummyTail.prev = this.dummyHead;
  }
  // 实现get方法
  get(key) {
    // 首先取出hash对象中这个键对应的节点
    let node = this.hash[key];
    // 如果这个节点不存在,返回-1
    if (node === undefined) return -1;
    // 如果这个节点存在的话,从链表中移除已有节点,然后再添加到头部
    this.deleteFromList(node);
    this.addToHead(node);
    return node.value;
  }
  // 实现put方法
  put(key,value) {
    // 首先取出哈希对象中这个键对应的节点
    let node = this.hash[key];
    // 分存在和不存在两种情况进行讨论
    if (node === undefined) {
      // 如果LRU是满的
      if (this.count === this.capacity) {
        // 取出最久未使用的
        let tail = this.dummyTail.prev;
        // 从LRU中删除
        this.deleteFromList(tail);
        // 从hash对象中删除
        delete this.hash[tail.key];
        // LRU的数量-1
        this.count--;
      }
      // 创造一个新的节点
      let newNode = new ListNode(key,value);
      this.hash[key] = newNode;
      this.addToHead(newNode);
      this.count++;
    } else {
      // 更新value
      node.value = value;
      this.deleteFromList(node);
      this.addToHead(node);
    }
  }
  deleteFromList(node) {
    let temp1 = node.prev;
    let temp2 = node.next;
    temp1.next = temp2;
    temp2.prev = temp1;
  }
  addToHead(node) {
    node.prev = this.dummyHead;
    node.next = this.dummyHead.next;
    this.dummyHead.next.prev = node;
    this.dummyHead.next = node;
  }
}
复制代码

题目反思

关于LRU缓存机制这个题目,我们可以采用Map做,也可以采用hash对象+链表的形式做,但是从题目简洁的程度看,Map的方法更加易懂,更加简洁。

相关文章
|
缓存 并行计算 PyTorch
PyTorch CUDA内存管理优化:深度理解GPU资源分配与缓存机制
本文深入探讨了PyTorch中GPU内存管理的核心机制,特别是CUDA缓存分配器的作用与优化策略。文章分析了常见的“CUDA out of memory”问题及其成因,并通过实际案例(如Llama 1B模型训练)展示了内存分配模式。PyTorch的缓存分配器通过内存池化、延迟释放和碎片化优化等技术,显著提升了内存使用效率,减少了系统调用开销。此外,文章还介绍了高级优化方法,包括混合精度训练、梯度检查点技术及自定义内存分配器配置。这些策略有助于开发者在有限硬件资源下实现更高性能的深度学习模型训练与推理。
2452 0
|
缓存 算法 数据挖掘
深入理解缓存更新策略:从LRU到LFU
【10月更文挑战第7天】 在本文中,我们将探讨计算机系统中缓存机制的核心——缓存更新策略。缓存是提高数据检索速度的关键技术之一,无论是在硬件还是软件层面都扮演着重要角色。我们会详细介绍最常用的两种缓存算法:最近最少使用(LRU)和最少使用频率(LFU),并讨论它们的优缺点及适用场景。通过对比分析,旨在帮助读者更好地理解如何选择和实现适合自己需求的缓存策略,从而优化系统性能。
754 3
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
287 0
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
329 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
存储 缓存 分布式计算
【赵渝强老师】Spark RDD的缓存机制
Spark RDD通过`persist`或`cache`方法可将计算结果缓存,但并非立即生效,而是在触发action时才缓存到内存中供重用。`cache`方法实际调用了`persist(StorageLevel.MEMORY_ONLY)`。RDD缓存可能因内存不足被删除,建议结合检查点机制保证容错。示例中,读取大文件并多次调用`count`,使用缓存后执行效率显著提升,最后一次计算仅耗时98ms。
483 0
【赵渝强老师】Spark RDD的缓存机制
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
602 4
|
缓存 Java 数据库连接
MyBatis缓存机制
MyBatis提供两级缓存机制:一级缓存(Local Cache)默认开启,作用范围为SqlSession,重复查询时直接从缓存读取;二级缓存(Second Level Cache)需手动开启,作用于Mapper级别,支持跨SqlSession共享数据,减少数据库访问,提升性能。
423 1
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?