原理
LRU(Least recently userd,最近最少使用),算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:
-
新数据插入到链表尾部;
-
每当缓存命中(即缓存数据被访问),则将数据移到链表尾部;
-
当链表满的时候,将链表头部的数据丢弃。
实现
使用一个Map存储键值对,由于Map是无序的,同时用一个双向链表把数据按顺序关联起来
public class LRUCache {
// 容量
private int capacity;
private Map<Integer, Node> map;
// 头节点
private Node head;
private Node tail;
public LRUCacheImpl(int capacity) {
this.capacity = capacity;
map = new HashMap<Integer, Node>();
}
public int get(int key) {
Node node = map.get(key);
// 缓存未命中,返回-1
if (node == null) {
return -1;
} else {
// 缓存命中,移动节点到尾部
removeNode(node);
offerNode(node);
return node.value;
}
}
// 添加一个节点到尾部
private void offerNode(Node node) {
if (tail != null) {
tail.next = node;
}
node.previs = tail;
node.next = null;
tail = node;
if (head == null) {
head = node;
}
}
// 移除一个节点
private void removeNode(Node node) {
if (node.previs != null) {
node.previs.next = node.next;
} else {
head = node.next;
}
if (node.next != null) {
node.next.previs = node.previs;
} else {
tail = node.previs;
}
}
// 新加一条数据
public void put(int key, int value) {
Node node = map.get(key);
if (node == null) {
if (map.size() >= capacity) {
map.remove(head.key);
removeNode(head);
}
Node newNode = new Node(key, value);
offerNode(newNode);
map.put(key, newNode);
} else {
node.value = value;
removeNode(node);
offerNode(node);
}
}
static class Node {
int key;
int value;
Node previs;
Node next;
public Node() {
}
Node(int key, int value) {
this.key = key;
this.value = value;
}
}