当前位置: 首页 > article >正文

算法必学之LRU

核心:最近最少使用的踢出缓存

实现:一个双向链表,越靠近尾部,最近越少使用,链表节点存储真正的数据key-value。数据集存储在HashMap中,标注头尾节点。

 package org.example.test01;
 ​
 import java.util.HashMap;
 import java.util.Map;
 ​
 ​
 public class LRUCache {
     // 这里的键,值,用int型为例
     // 双向链表节点,真正数据key-value所在
     class DLinkedNode {
         int key;
         int value;
         DLinkedNode prev;
         DLinkedNode next;
         public DLinkedNode() {
 ​
         }
 ​
         public DLinkedNode(int key, int value) {
             this.key = key;
             this.value = value;
         }
     }
 ​
     // 真正缓存的数据集,存储key-双向链表节点
     private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
 ​
     // 当前缓存大小
     private int size;
     // 缓存容量
     private int capacity;
     // 头尾指针,方便我们操作
     private DLinkedNode head, tail;
 ​
     // 初始化LRU缓存
     public LRUCache(int capacity) {
         this.size = 0;
         this.capacity = capacity;
 ​
         head = new DLinkedNode();
         tail = new DLinkedNode();
 ​
         head.next = tail;
         tail.prev = head;
 ​
 ​
     }
 ​
     // 判断缓存中是否有该key,
     // 没有就get不到,返回-1
     // 有就刷新最新最近使用,也就是将对应数据的链表节点移到头部
     public int get(int key) {
         DLinkedNode node = cache.get(key);
         if (node == null) {
             return -1;
         }
 ​
         moveToHead(node);
         return node.value;
     }
 ​
     // 判断缓存中是否有该key,
     // 没有就put一个,也就是创建新的链表节点,放入缓冲区中,设置好对应头结点,
     // 但若超过容量需要删除尾部节点
     // 有就直接修改对应值,并更新最新最近使用数据
     public void put(int key, int value) {
 ​
         DLinkedNode node = cache.get(key);
 ​
         if (node == null) {
             DLinkedNode newNode = new DLinkedNode(key, value);
             cache.put(key, newNode);
             addToHead(newNode);
             ++size;
             if (size > capacity) {
                 // 如果超出容量,删除双向链表的尾部节点
                 DLinkedNode tail = removeTail();
                 // 删除哈希表中对应的项
                 cache.remove(tail.key);
                 --size;
             }
         } else {
             node.value = value;
             moveToHead(node);
         }
 ​
     }
     
     private DLinkedNode removeTail() {
         DLinkedNode res = tail.prev;
         removeNode(res);
         return res;
     }
 ​
 ​
     // 这里是将该节点相应位置删除,再插入头部,达到移动数据(更新最近使用)的数据的效果
     private void moveToHead(DLinkedNode node) {
         removeNode(node);
         addToHead(node);
     }
 ​
     // 头部添加节点,需要头部节点跟当前节点建立联系,
     // 但在此之前需要当前节点尾部跟原来的数据建立联系,
     // 这样头部就放心跟当前节点建立联系。
     private void addToHead(DLinkedNode node) {
         // 当前节点尾部跟原来的数据建立联系
         node.next = head.next;
         head.next.prev = node;
         // 头部放心跟当前节点建立联系
         head.next = node;
         node.prev = head;
     }
 ​
     // 删除只需要当前节点前一个后一个节点建立联系就行
     private void removeNode(DLinkedNode node) {
 ​
         node.prev.next = node.next;
         node.next.prev = node.prev;
 ​
     }
 ​
 ​
 }


http://www.kler.cn/news/328768.html

相关文章:

  • Gson将对象转换为JSON(学习笔记)
  • 【C++高阶】深入理解C++智能指针:掌握RAII与内存安全的利器
  • 南沙C++信奥赛陈老师解一本通题 2005:【20CSPJ普及组】直播获奖
  • Vue3.X + SpringBoot小程序 | AI大模型项目 | 饮食陪伴官
  • Python知识点:如何使用AWS Greengrass与Python进行边缘计算
  • 64 注意力机制_by《李沐:动手学深度学习v2》pytorch版
  • 【计网】从零开始学习http协议 --- http的请求与应答
  • Stable Diffusion绘画 | 来训练属于自己的模型:素材准备篇
  • 【AI知识点】嵌入向量(Embedding Vector)
  • 明达技术工业级边缘计算网关:智能制造的智慧纽带
  • Docker安装consul + go使用consul + consul知识
  • WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!
  • 墙绘艺术在线市场:SpringBoot实现指南
  • 基于微信小程序爱心领养小程序设计与实现(源码+参考文档+定制开发)
  • 【如何实现一个神经网络】(一)神经元和神经网络
  • C0004.Qt中QComboBox设置下拉列表样式后,下拉列表样式无效的解决办法
  • 【分布式微服务云原生】探索Dubbo:接口定义语言的多样性与选择
  • E35.【C语言】判断大/小端序
  • Java | Leetcode Java题解之第446题等差数列划分II-子序列
  • 虚幻引擎-设置UI自适应屏幕大小
  • 前端框架React的详细的学习方法和过程
  • Apache安装后无法启动的问题“不能再本地计算机启动apache”
  • SOMEIP_ETS_146: SD_ResetInterface
  • 【刷点笔试面试题试试水】不使用任何中间变量如何将a、b的值进行交换?
  • docker如何查看容器的ip
  • 文件的管理
  • Qt6 中相对于 Qt5 的新增特性及亮点
  • 部署(swoft+swoole)网站
  • 雅达利“美洲虎“游戏机在iPhone模拟应用程序中重生
  • Maven和pnpm依赖迁移