手写LRU缓存
创始人
2025-05-28 18:51:58

要求

设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。
get和put函数的时间复杂度因为O(1)

技术栈

HashMap和双向链表=LinkedHashMap的链式版本
HashMap:存放缓存数据
双向链表:存放节点顺序

举例

缓存容量:2
依次进行以下操作:
1. put(1,1)
2. put(2,2)
3. get(1)
3. put(3,3)
4. put(4,4)

图1 初始化虚拟头节点和尾节点

  1. put(1,1)

图2 插入1

  1. put(2,2)

图3 插入2

  1. get(1)

图4 获取key为1的值

由于要删除最近访问的值,因此将key为1的节点移到头节点
细节:先移除,再移动(这里要注意顺序,不然容易出问题,如果先移动到头节点,再移除会出错,如图5)。

图5 先移动后移除图

  1. put(3,3)

图6 put(3,3)

由于此时缓存元素为2,再插入一个元素,超过缓存容量,所以需要移除尾节点。然后将插入的元素移动到头部,如图6所示。
  1. put(4,4)

图7 put(4,4)

解释如4所示。

LRU缓存代码

class LRUCache {int size;                           // 元素个数int capacity;                       // 容量BiNode head;                        // 头节点BiNode tail;                        // 尾节点Map cache;         // 缓存public LRUCache(int capacity) {this.size = 0;this.capacity = capacity;this.cache = new HashMap<>();head = new BiNode();tail = new BiNode();head.next = tail;tail.pre = head;}public int get(int key) {BiNode node = cache.get(key);if (node == null) {return -1; // 不存在该元素} else {removeNode(node);   // 移除老元素addToHead(node);    // 放到头部return node.value;}}public void put(int key, int value) {BiNode node = cache.get(key);if(node == null){               // 不存在该元素BiNode newNode = new BiNode(key, value);addToHead(newNode);          // 放到头部cache.put(key, newNode);     // 放入缓存size++;if(size > capacity){int K = tail.pre.key;   // 移除的keycache.remove(K);        // 从缓存移除removeTailNode();       // 移除尾部节点size--;}}else {                         // 存在该元素BiNode newNode = new BiNode(key, value);addToHead(newNode);         // 放到头部removeNode(node);           // 移除老节点cache.put(key, newNode);    // 放入缓存}}private void removeNode(BiNode node){node.next.pre = node.pre;node.pre.next = node.next;}private void removeTailNode(){BiNode node = tail.pre;removeNode(node);node = null; // help GC}private void addToHead(BiNode node){node.next = head.next;node.next.pre = node;node.pre = head;head.next = node;}class BiNode{BiNode pre;     // 前向指针BiNode next;    // 后向指针int key;        // keyint value;      // valuepublic BiNode(){}public BiNode(int K, int V){key = K;value = V;}}}

相关内容

热门资讯

玛雅人的五大预言 玛雅人预言2... 曾经玛雅人预言2012年是世界末日,但当时好像没有发生什么。没想到10年后的2022年,疫情,战争,...
cad打印线条粗细设置 cad... 004-线型(下)打印样式设置和线型文件使用一、线宽设置方法制图规范里边的线宽要求,我们已经定义好,...
荼蘼什么意思 岁月缱绻葳蕤生香... 感谢作者【辰夕】的原创独家授权分享编辑整理:【多肉植物百科】百科君坐标:云南 曲靖春而至,季节流转,...
cad打印线条粗细设置 cad... 004-线型(下)打印样式设置和线型文件使用一、线宽设置方法制图规范里边的线宽要求,我们已经定义好,...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...