public class Solution {
/**
* lru的核心思想是最新使用或者最近创建的放置在链表的头部,越靠后说明距离上次使用越长,删除后面的元素即可,
* 因为涉及到删除元素所以使用双向链表更加适合
*/
// lru支持的总容量
int capacity;
// 已经使用的容量
int size;
// 缓存
Map<Integer, ListNode> cache;
// 头结点
ListNode head;
// 尾结点
ListNode tail;
public Solution(int capacity) {
this.capacity = capacity;
this.size = 0;
cache = new HashMap();
head = new ListNode();
tail = new ListNode();
head.next = tail;
tail.pre = head;
}
// 从缓存中获取
public int get(int key) {
ListNode node = cache.get(key);
if (node != null) {
// remove node to head
removeToHead(node);
return node.value;
}
return -1;
}
public void set(int key, int value) {
ListNode node = cache.get(key);
if (node == null) {
// 缓存中不存在,存储即可
ListNode newNode = new ListNode(key, value);
addToHead(newNode);
cache.put(key, newNode);
size++;
if (size > capacity) {
// remove last node ;
ListNode dNode = removeLastNode();
cache.remove(dNode.key);
size--;
}
} else {
// key 已经存在,值有可能相同也可能不相同,直接覆盖即可
node.value = value;
// 修改缓存的值
cache.put(key, node);
// remove this node to head
removeToHead(node);
}
}
// 移除最后一个元素
public ListNode removeLastNode() {
// head >> 1 >> 2 >> 3 >> tail
ListNode delNode = tail.pre;
removeNode(delNode);
return delNode;
}
// 移动节点到头节点
public void removeToHead(ListNode node) {
// 删除当前节点元素
removeNode(node);
// 在头结点处新增元素
addToHead(node);
}
// 移除指定元素
public void removeNode(ListNode node) {
// head >> 1 >> 2 >> 3 >> tail
// 假设需要移除元素2,则先需要获取2的前置元素1 让1指向删除元素的下一个元素。即 pre.next = node.next ;
ListNode pre = node.pre;
pre.next = node.next;
node.next.pre = pre;
}
// 头节点添加元素
public void addToHead(ListNode node) {
// head >> 2 >> 3 >> tail
// 假设需要向头节点添加元素1,因为目前的head是我们虚拟的一个头结点,所以只需要获取head.next指向新增的节点即可;
ListNode temp = head.next;
head.next = node;
node.pre = head;
node.next = temp;
temp.pre = node;
}
class ListNode {
int key;
int value;
ListNode next;
ListNode pre;
ListNode() {
}
ListNode(int key, int value) {
this.key = key;
this.value = value;
}
}
}
LRU算法
于 2023-12-26 15:09:33 首次发布
