一个优雅的LRU缓存 Java 实现
Java 实现 LRU缓存
LRU算法是一种常用的缓存算法,用于移除最近最少使用的数据。LRU缓存的核心思想是:当缓存容量已满,且需要插入新数据时,优先移除最近最少使用的数据。这种算法在许多场景下都非常有用,比如数据库缓存、网页缓存等。它可以帮助我们高效地管理有限的存储空间,同时保证最近访问的数据能够快速获取。
实现思路
为了实现一个高效的LRU缓存,我们需要结合两种数据结构:哈希表和双向链表。
- 哈希表:用于快速定位缓存中的数据。通过键(key)可以快速找到对应的节点。
- 双向链表:用于维护数据的访问顺序。最近访问的节点会被移动到链表的头部,而最久未访问的节点则位于链表的尾部。
这种结合方式的优势在于:
- 哈希表提供了快速的查找能力,时间复杂度为O(1)。
- 双向链表可以方便地移动节点,同时维护访问顺序。
以下是LRU缓存的完整实现代码:
public class LRUCache {
private int capacity; // 缓存容量
private Map<Integer, Node> map; // 哈希表,用于快速查找
private Node head; // 双向链表的头节点
private Node tail; // 双向链表的尾节点
/**
* 构造函数,初始化属性字段。虚拟的头节点head和尾节点tail可以简化链表操作。
*/
public LRUCache(int capacity) {
this.capacity = capacity;
map = new HashMap<>();
head = new Node();
tail = new Node();
head.next = tail;
tail.prev = head;
}
/**
* 如果键存在于哈希表中,获取对应的节点,并将其移动到链表头部。如果键不存在,返回-1。
*/
public int get(int key) {
if(map.containsKey(key)){
Node node = map.get(key);
move2First(node);
return node.val;
}
return -1;
}
/**
* 如果键已存在,更新节点的值,并将其移动到链表头部。
* 如果键不存在,检查缓存是否已满:
* 如果未满,创建新节点并插入。
* 如果已满,移除链表尾部的节点(最久未访问的节点),并用新节点替换。
*/
public void put(int key, int value) {
if(map.containsKey(key)){
Node node = map.get(key);
node.val = value;
move2First(node);
}else{
Node node;
if(map.size() < capacity) node = new Node(key, value);
else{
node = tail.prev;
map.remove(node.key);
node.val = value;
node.key = key;
}
map.put(key, node);
move2First(node);
}
}
/**
* 将节点移动到链表头部
*/
public void move2First(Node node){
if(node == head.next) return;
if(node.next != null) node.prev.next = node.next;
if(node.prev != null) node.next.prev = node.prev;
head.next.prev = node;
node.next = head.next;
node.prev = head;
head.next = node;
}
// 测试案例
public static void main(String[] args) {
LRUCache cache = new LRUCache(2); // 缓存容量为2
cache.put(1, 1);
cache.put(2, 2);
System.out.println(cache.get(1)); // 返回1
cache.put(3, 3); // 移除键2
System.out.println(cache.get(2)); // 返回-1(键2已被移除)
cache.put(4, 4); // 移除键1
System.out.println(cache.get(1)); // 返回-1(键1已被移除)
System.out.println(cache.get(3)); // 返回3
System.out.println(cache.get(4)); // 返回4
}
}
// 双向链表节点
class Node{
Node next;
Node prev;
int val;
int key;
Node(){ }
Node(int key, int val){
this.val = val;
this.key = key;
}
}

浙公网安备 33010602011771号