LeetCode LRU演算法

LRU(Least recently used,最近最少使用)演算法是目前廣泛使用的緩存淘汰演算法。演算法思想是如果數據最近被訪問(讀或寫),那麼將來被訪問的概率也更高。所以長期不被訪問的數據將會被淘汰。

LeetCode的146題要求實現這一演算法。

public class LRUCache { private final int capacity; private Map<Integer, Integer> map; public LRUCache(int capacity) { this.capacity = capacity; this.map = new LinkedHashMap<Integer, Integer>() { private static final long serialVersionUID = 23L; @Override protected boolean removeEldestEntry(java.util.Map.Entry<Integer, Integer> eldest) { return size() > LRUCache.this.capacity; } }; } public int get(int key) { Integer value = map.get(key); if (value != null) { map.remove(key); map.put(key, value); } else { value = -1; } return value; } public void put(int key, int value) { if (map.containsKey(key)) { map.remove(key); } map.put(key, value); }}

從當時的運行效果來看,幾乎完美。但LeetCode的cases可能發生變動,現在重新提交這段代碼,效果就大不如從前了。

上面這段代碼可以繼續優化。

public LRUCache(int capacity) { this.capacity = capacity; this.map = new LinkedHashMap<Integer, Integer>(32, 0.75f, true) { private static final long serialVersionUID = 23L; @Override protected boolean removeEldestEntry(java.util.Map.Entry<Integer, Integer> eldest) { return size() > LRUCache.this.capacity; } };}

LinkedHashMap本就可以按照訪問訪問順序排序,當時沒有注意到這個構造方法。其餘代碼略去。

從LinkedHashMap的構造方法來看,可以分成兩類:按插入順序排序,按訪問順序排序

我的提交代碼非常依賴LinkedHashMap這種數據結構,從類名上看來,它和HashMap必然有所關係。其實它是HashMap的子類,在HashMap基礎上增加排序功能,讓輸出順序與插入順序或者訪問順序相同,即最後一個插入(或訪問)的元素最後一個輸出。

HashMap的實現依賴鏈表數組(數組的每個元素是鏈表),但裡面的元素是無序的。LinkedHashMap在其基礎之上,增加了一個鏈表來記錄元素的順序。

通過對比這兩類,完美體現了面向對象編程的繼承機制,需要深刻體會!

學習一個類的最基本最重要的方法就是JDK文檔。一段官方文檔,勝過千句啰嗦。

Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries.

LinkedHashMap還可以在某種特點條件下removeEldestEntry,這也是實現LRU演算法的一個關鍵。

Returns true if this map should remove its eldest entry. This method is invoked by put and putAll after inserting a new entry into the map. It provides the implementor with the opportunity to remove the eldest entry each time a new one is added. This is useful if the map represents a cache: it allows the map to reduce memory consumption by deleting stale entries.

常見用法:

private static final int MAX_ENTRIES = 100;protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES;}

原題:LRU Cache

參考資料:LinkedHashMap (Java Platform SE 8 )

推薦閱讀:

K近鄰演算法(內附Kd-tree視頻演示)
數組中出現次數超過一半的數字
九章演算法 | Google 面試題:字典裡面的最長單詞
調整數組順序使奇數位於偶數前面
連續子數組的最大和

TAG:LeetCode | 演算法 | 緩存 |