算法必学之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;
 ​
     }
 ​
 ​
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值