(链表)19-LRU缓存

发布时间 2023-11-19 21:23:08作者: StringBuilder

  1 public class LRUCache {
  2 
  3     // 双向链表节点的构造函数
  4     class DLinkedNode {
  5         // 双向链表-Key
  6         int key;
  7         // 双向链表-Val
  8         int value;
  9         // 双向链表-前指针
 10         DLinkedNode pre;
 11         // 双向链表-后指针
 12         DLinkedNode next;
 13         // 构造函数-空参数
 14         public DLinkedNode() {
 15         }
 16         // 构造函数-完全参数
 17         public DLinkedNode(int inputKey, int inputVal) {
 18             key = inputKey; 
 19             value = inputVal;
 20         }
 21     }
 22 
 23     // 哈希表
 24     private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
 25     // LRU缓存-已填充的数据量
 26     private int size;
 27     // LRU缓存-容量
 28     private int capacity;
 29     // 伪头结点
 30     private DLinkedNode head;
 31     // 伪尾结点
 32     private DLinkedNode tail;
 33 
 34     // LRU缓存构造函数
 35     public LRUCache(int capacity) {
 36         this.size = 0;
 37         this.capacity = capacity;
 38         // 添加伪头部和伪尾部节点
 39         head = new DLinkedNode();
 40         tail = new DLinkedNode();
 41         head.next = tail;
 42         tail.pre = head;
 43     }
 44 
 45     public int get(int key) {
 46         DLinkedNode node = cache.get(key);
 47         // KEY不存在返回-1
 48         if (node == null) {
 49             return -1;
 50         }
 51         // 如果KEY存在-先通过哈希表定位-再移到头部
 52         moveToHead(node);
 53         // 返回KEY对应节点值
 54         return node.value;
 55     }
 56 
 57     public void put(int key, int value) {
 58         DLinkedNode node = cache.get(key);
 59         if (node == null) {
 60             // KEY不存在-创建一个新的节点
 61             DLinkedNode newNode = new DLinkedNode(key, value);
 62             // 添加进哈希表
 63             cache.put(key, newNode);
 64             // 添加至双向链表的头部
 65             addToHead(newNode);
 66             // 数据量+1
 67             size ++;
 68             if (size > capacity) {
 69                 // 超出容量,删除双向链表的尾部节点
 70                 DLinkedNode tail = removeTail();
 71                 // 删除哈希表中对应的项
 72                 cache.remove(tail.key);
 73                 // 数据量-1
 74                 size --;
 75             }
 76         } else {
 77             // KEY存在-先通过哈希表定位修改VAL
 78             node.value = value;
 79             // 将刚刚使用的节点移到头部
 80             moveToHead(node);
 81         }
 82     }
 83 
 84     // 将入参节点添加到头结点
 85     private void addToHead(DLinkedNode node) {
 86         node.pre = head;
 87         node.next = head.next;
 88         head.next.pre = node;
 89         head.next = node;
 90     }
 91 
 92     // 删除入参节点
 93     private void removeNode(DLinkedNode node) {
 94         node.pre.next = node.next;
 95         node.next.pre = node.pre;
 96     }
 97 
 98     // 将入参节点移动到链表最前面
 99     private void moveToHead(DLinkedNode node) {
100         removeNode(node);
101         addToHead(node);
102     }
103 
104     // 移除尾部结点-返回移除的节点
105     private DLinkedNode removeTail() {
106         DLinkedNode res = tail.pre;
107         removeNode(res);
108         return res;
109     }
110 }