簡介
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算法。