Least Recently Used (LRU) cache
概念:淘汰最近最少访问数据的缓存策略。
/**
* 通过继承LinkedHashMap,设置链表排序方式为访问顺序排序之后,通过重写其removeEldestEntry方法来实现。
*/
import java.util.LinkedHashMap;
import java.util.Map;
class LRUCache extends LinkedHashMap<Integer, Integer> {
private int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75F, true); // 容量,加载因子,是否根据访问顺序排序(true:根据访问顺序排序;false根据插入顺序排序)
this.capacity = capacity;
}
public int get(int key) {
return super.getOrDefault(key, -1);
}
public void put(int key, int value) {
super.put(key, value);
}
// 在put方法中会调用removeEldestEntry方法来来判断:在新增元素后,最老的元素是否需要删除。
// 默认返回false:false表示新增元素后不删除最老的元素
// 重写该方法后:可以自定义条件来控制新增元素之后是否要删除最老的元素。
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > capacity;
}
}
/**
* 使用 哈希表+双向链表 来实现LRU缓存:哈希表存储数据,双向链表存储并维护元素的访问顺序。
*/
import java.util.HashMap;
public class LRUCache {
private HashMap<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>(); // 存储数据
private int size; // 当前集合中元素的数量
private int capacity; // 缓存的容量
private DLinkedNode head; // 伪头结点,作为哨兵,方便双向链表的维护。
private DLinkedNode tail; // 伪尾节点,作为哨兵,方便双向链表的维护。
class DLinkedNode {
int key;
int value;
DLinkedNode prev;
DLinkedNode next;
}
/**
* 将新插入的节点添加到伪头节点head的后面(即链表的头节点),链表中节点是按照最近访问的顺序来排列的。
*/
private void addNode(DLinkedNode node) {
// 双向链表,插入一个节点需要维护4个指针。
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
private void removeNode(DLinkedNode node) {
DLinkedNode prev = node.prev;
DLinkedNode next = node.next;
prev.next = next;
next.prev = prev;
node.prev = null;
node.next = null;
}
private void moveToHead(DLinkedNode node) {
removeNode(node);
addNode(node);
}
private DLinkedNode popTail() {
DLinkedNode res = tail.prev;
removeNode(res);
return res;
}
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
DLinkedNode node = cache.get(key);
if (node == null) return -1;
// move the accessed node to the head;
moveToHead(node);
return node.value;
}
public void put(int key, int value) {
DLinkedNode node = cache.get(key);
if (node == null) {
DLinkedNode newNode = new DLinkedNode();
newNode.key = key;
newNode.value = value;
cache.put(key, newNode);
addNode(newNode);
++size;
if (size > capacity) {
DLinkedNode tail = popTail();
cache.remove(tail.key);
--size;
}
} else {
node.value = value;
moveToHead(node);
}
}
}
LRU - 最近最少访问缓存策略
于 2020-03-05 22:04:37 首次发布