LRU算法会淘汰最久未使用的元素
插入和查询时间复杂度都要求O(1),因此使用 链表+HashMap实现
/**
* 使用 链表+HashMap 实现LRU
*/
public class LRUCache {
private ListNode head; // 头结点占位, 避免判空操作
private ListNode tail; // 尾节点占位, 避免判空操作
private Map<Integer, ListNode> cache;
private int capacity; // 容量
private int size; // 存储元素个数
/**
* 初始化容量为 capacity 的LRU缓存
*/
public LRUCache(int capacity) {
this.capacity = capacity;
this.head = new ListNode();
this.tail = new ListNode();
this.head.setNext(this.tail);
this.cache = new HashMap<>();
}
/**
* 查询元素, 如果不存在, 返回-1
*/
public int get(int key) {
ListNode node = cache.get(key);
if (node == null) return -1; // 没有目标元素
moveToHead(node); // 这个节点被访问了, 移到队头
return node.val;
}
/**
* 插入元素
*/
public void put(int key, int value) {
ListNode node = cache.get(key);
if (node != null) { // 存在, 更新值, 移到队头
node.val = value;
moveToHead(node);
return;
}
node = new ListNode(key, value); // 不存在, 创建, 放到队头
this.head.append(node);
cache.put(key, node);
size++;
eliminate(); // 淘汰元素
}
private void eliminate() {
if (size > capacity) {
size--;
ListNode remove = tail.pre;
remove.remove(); // 淘汰末尾元素
cache.remove(remove.key);
}
}
private void moveToHead(ListNode node) {
node.remove(); // 从链表中移除
this.head.append(node); // 添加到队头
}
private static class ListNode {
public int key;
public int val;
public ListNode next;
public ListNode pre;
public ListNode() {
}
public ListNode(int key, int val) {
this.key = key;
this.val = val;
}
public void append(ListNode element) {
ListNode next = this.next;
this.setNext(element);
element.setNext(next);
}
public void remove() {
if (pre != null) {
pre.setNext(next);
this.pre = null;
}
this.next = null;
}
private void setNext(ListNode next) {
this.next = next;
if (next != null) {
next.pre = this;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
ListNode cur = this;
while (cur != null) {
sb.append(cur.key).append(":").append(cur.val).append(", ");
cur = cur.next;
}
if (sb.length() > 0) {
return sb.substring(0, sb.length() - 2);
}
return "";
}
}
}