简介
LRU(Least recently used),即最近最少使用,核心思想是如果数据最近被访问过,那么将来被访问的几率也更高。
代码实现1
import java.util.LinkedHashMap;
import java.util.Map.Entry;
class LRUCache<K, V> {
private LinkedHashMap<K, V> map;
public LRUCache(int capacity) {
map = new LinkedHashMap<>(capacity, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Entry<K, V> eldest) {
return size() > capacity;
}
};
}
public V get(K key) {
return map.get(key);
}
public void put(K key, V value) {
map.put(key, value);
}
public static void main(String[] args) {
LRUCache<Integer, Integer> lRUCache = new LRUCache<>(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
System.out.println(lRUCache.get(1));//返回 1 缓存是 {2=2,1=1}
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
System.out.println(lRUCache.get(2));// 返回 null (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {3=3,4=4}
System.out.println(lRUCache.get(1));//返回 null (未找到)
System.out.println(lRUCache.get(3));//返回 3
System.out.println(lRUCache.get(4));//返回 4
}
}
LRU算法主要有两种操作添加put和获取get,需要使用到哈希表和双向链表两种数据结构,java内置的LinkedHashMap结合了这两种。访问一个元素之后就会将该元素移动到链表的末尾,如果添加元素之后发现超出容量,删除链表头部的元素。
代码实现2
import java.util.HashMap;
class LRUCache2<K, V> {
private HashMap<K, Node<K, V>> cache;
private Node<K, V> head;
private Node<K, V> tail;
private int capacity;
public LRUCache2(int capacity) {
this.capacity = capacity;
cache = new HashMap<>(capacity);
}
public V get(K key) {
Node<K, V> node = cache.get(key);
if (node == null) {
return null;
}
moveToTail(node);
return node.value;
}
public void put(K key, V value) {
Node<K, V> node = cache.get(key);
if (node != null) {
node.value = value;
moveToTail(node);
} else {
Node<K, V> newNode = new Node<>(key, value);
cache.put(key, newNode);
addToTail(newNode);
//如果超出容量,删除链表头结点
if (cache.size() > capacity) {
cache.remove(head.key);
removeNode(head);
}
}
}
/**
* 将e节点移动到链表尾部
*/
private void moveToTail(Node<K, V> e) {
removeNode(e);
addToTail(e);
}
private void addToTail(Node<K, V> e) {
//将e链接到tail后面
if (tail == null) {
head = e;
} else {
tail.next = e;
e.prev = tail;
}
tail = e;
}
private void removeNode(Node<K, V> e) {
Node<K, V> prev = e.prev;
Node<K, V> next = e.next;
//删除e节点
e.prev = e.next = null;
if (prev == null) {
head = next;
} else {
prev.next = next;
}
if (next == null) {
tail = prev;
} else {
next.prev = prev;
}
}
static class Node<K, V> {
K key;
V value;
Node<K, V> prev;
Node<K, V> next;
Node(K key, V value) {
this.key = key;
this.value = value;
}
}
public static void main(String[] args) {
LRUCache2<Integer, Integer> lRUCache = new LRUCache2<>(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
System.out.println(lRUCache.get(1));//返回 1 缓存是 {2=2,1=1}
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
System.out.println(lRUCache.get(2));// 返回 null (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {3=3,4=4}
System.out.println(lRUCache.get(1));//返回 null (未找到)
System.out.println(lRUCache.get(3));//返回 3
System.out.println(lRUCache.get(4));//返回 4
}
}
通过自己实现的双向链表和java的哈希表来实现LRU算法。