LRU快取機制,全稱Least Recently Used,字面意思就是最近最少使用,是一種快取淘汰策略。換句話說,LRU機制就是認為最近使用的資料是有用的,很久沒用過的資料是無用的,當記憶體滿了就優先刪除很久沒有使用的資料。
基於LeetCode146,可以使用雜湊連結串列或者自定義雙端連結串列類+雜湊表兩種方法來實現LRU快取機制。
它應該支援以下操作:獲取資料get
和 寫入資料put
。
獲取資料get(key)
:如果金鑰 (key) 存在於快取中,則獲取金鑰的值(總是正數),否則返回-1
。
寫入資料put(key, value)
:如果金鑰不存在,則寫入其資料值。當快取容量達到上限時,它應該在寫入新資料之前刪除最近最少使用的資料值,從而為新的資料值留出空間。
1. 基於LinkedHashMap實現LRU快取機制
class LRUCache {
Map<Integer, Integer> map;
int capacity;
public LRUCache(int capacity) {
this.capacity = capacity;
map = new LinkedHashMap<>();
}
public int get(int key) {
// 若key不存在返回-1
if(!map.containsKey(key)) return -1;
// 若key存在則獲取key對應的val
int val = map.get(key);
// 更新位置
put(key, val);
return val;
}
public void put(int key, int val) {
// 若快取命中則先刪除資料在重新放入以更新位置
if(map.containsKey(key)) {
map.remove(key);
map.put(key, val);
} else {
// 若快取未命中則先判斷是否達到最大容量
// 超出容量則刪除最久沒有使用的資料(利用迭代器刪除第一個)
if (capacity == map.size()) map.remove(map.keySet().iterator().next());
// 刪除完成後存放新資料
map.put(key, val);
}
}
}
2. 基於DoubleList與HashMap實現LRU快取機制
如果不使用LinkedHashMap,可以自己造輪子,自定義DoubleList
類並結合HashMap
實現與LinkedHashMap相同的功能。
class LRUCache {
int capacity;
DoubleList cache;
Map<Integer, Node> map;
public LRUCache(int capacity) {
this.capacity = capacity;
cache = new DoubleList();
map = new HashMap<>();
}
public int get(int key) {
if(!map.containsKey(key)) return -1;
int val = map.get(key).val;
put(key, val);
return val;
}
public void put(int key, int val) {
Node node = new Node(key, val);
if(map.containsKey(key)) {
cache.remove(map.get(key));
cache.addFirst(node);
map.put(key, node);
} else {
if(capacity == cache.size) map.remove(cache.removeLast().key);
cache.addFirst(node);
map.put(key, node);
}
}
}
class DoubleList {
Node head, tail;
int size;
public DoubleList() {
head = new Node(0, 0);
tail = new Node(0, 0);
head.next = tail;
tail.prev = head;
size = 0;
}
public void addFirst(Node node) {
Node temp = head.next;
node.next = temp;
temp.prev = node;
head.next = node;
node.prev = head;
size++;
}
public void remove(Node node) {
Node temp = node.prev;
temp.next = node.next;
temp.next.prev = temp;
size--;
}
public Node removeLast() {
if (size == 0) return null;
Node del = tail.prev;
remove(del);
return del;
}
}
class Node {
int key, val;
Node prev, next;
public Node(int key, int val) {
this.key = key;
this.val = val;
}
}