LRU(Least Recently Used)是一种缓存淘汰算法,最近最少使用的缓存项会被淘汰。
我们可以使用双向链表与哈希表实现 LRU 算法:
public class LRUCache {
class ListNode {
int key;
int val;
ListNode prev;
ListNode next;
ListNode(int key, int val) {
this.key = key;
this.val = val;
}
}
private int capacity;
private HashMap<Integer, ListNode> map;
private ListNode head;
private ListNode tail;
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>();
}
public int get(int key) {
if (!map.containsKey(key)) return -1;
ListNode node = map.get(key);
remove(node);
addToHead(node);
return node.val;
}
public void put(int key, int val) {
if (map.containsKey(key)) {
ListNode node = map.get(key);
node.val = val;
remove(node);
addToHead(node);
} else {
if (map.size() == capacity) {
map.remove(tail.key);
removeTail();
}
ListNode node = new ListNode(key, val);
addToHead(node);
map.put(key, node);
}
}
private void remove(ListNode node) {
ListNode prev = node.prev;
ListNode next = node.next;
prev.next = next;
next.prev = prev;
}
private void addToHead(ListNode node) {
node.next = head.next;
node.prev = head;
head.next.prev = node;
head.next = node;
}
private void removeTail() {
ListNode prev = tail.prev;
prev.next = null;
tail = prev;
}
}
所以,LRU 缓存淘汰算法的实现步骤为:
- 使用双向链表存储缓存项,最近使用的项靠近头部。
- 使用哈希表记录每个缓存项在链表中的位置。
- get 操作:如果 key 存在,则返回对应值,并将该项移到链表头部。
- put 操作:如果 key 存在,则更新值,并将该项移到链表头部。如果不存在,添加至链表头部。如果达到容量,则删除链表尾部项。
- 删除链表尾部项时,同时需要从哈希表中移除。
- 特殊情况:如果链表为空,添加的第一项既是头部又是尾部项。
LRU 算法可以有效地实现缓存淘汰,保证最近使用的缓存数据时刻可用。会使用代码实现 LRU 算法,可以让我们熟练掌握链表、哈希表等数据结构,这是算法与编程的重要基础。
LRU 缓存淘汰算法这一经典问题涉及到链表、哈希表、插入、删除等知识点与技能。深入理解和掌握这些基本工具,可以让我们具备解决算法与编程更高难度问题的能力。