如何用LinkedHashMap實現LRU快取演算法
阿新 • • 發佈:2019-02-08
阿里巴巴筆試考到了LRU,一激動忘了怎麼回事了。。準備不充分啊。。
快取這個東西就是為了提高執行速度的,由於快取是在寸土寸金的記憶體裡面,不是在硬盤裡面,所以容量是很有限的。LRU這個演算法就是把最近一次使用時間離現在時間最遠的資料刪除掉。先說說List:每次訪問一個元素後把這個元素放在 List一端,這樣一來最遠使用的元素自然就被放到List的另一端。快取滿了t的時候就把那最遠使用的元素remove掉。但更實用的是HashMap。因為List太慢,要刪掉的資料總是位於List底層陣列的第一個位置,刪掉之後,後面的資料要向前補位。。所以複雜度是O(n),那就用連結串列結構的LinkedHashMap唄~,LinkedHashMap預設的元素順序是put的順序,但是如果使用帶引數的建構函式,那麼LinkedHashMap會根據訪問順序來調整內部 順序。 LinkedHashMap的get()方法除了返回元素之外還可以把被訪問的元素放到連結串列的底端,這樣一來每次頂端的元素就是remove的元素。
建構函式如下:
public LinkedHashMap (int initialCapacity, float loadFactor, boolean accessOrder);
initialCapacity 初始容量
loadFactor 載入因子,一般是 0.75f
accessOrder false 基於插入順序 true 基於訪問順序(get一個元素後,這個元素被加到最後,使用了LRU 最近最少被使用的排程演算法)
來個例子吧:輸出 7import java.util.*; class Test { public static void main(String[] args) throws Exception{ Map<Integer,Integer> map=new LinkedHashMap<>(10,0.75f,true); map.put(9,3); map.put(7,4); map.put(5,9); map.put(3,4); //現在遍歷的話順序肯定是9,7,5,3 //下面訪問了一下9,3這個鍵值對,輸出順序就變嘍~ map.get(9); for(Iterator<Map.Entry<Integer,Integer>> it=map.entrySet().iterator();it.hasNext();){ System.out.println(it.next().getKey()); } } }
5
3
9 好玩吧~ 下面開始實現LRU快取嘍~
輸出結果如下 9=3import java.util.*; //擴充套件一下LinkedHashMap這個類,讓他實現LRU演算法 class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{ //定義快取的容量 private int capacity; private static final long serialVersionUID = 1L; //帶引數的構造器 LRULinkedHashMap(int capacity){ //呼叫LinkedHashMap的構造器,傳入以下引數 super(16,0.75f,true); //傳入指定的快取最大容量 this.capacity=capacity; } //實現LRU的關鍵方法,如果map裡面的元素個數大於了快取最大容量,則刪除連結串列的頂端元素 @Override public boolean removeEldestEntry(Map.Entry<K, V> eldest){ System.out.println(eldest.getKey() + "=" + eldest.getValue()); return size()>capacity; } } //測試類 class Test{ public static void main(String[] args) throws Exception{ //指定快取最大容量為4 Map<Integer,Integer> map=new LRULinkedHashMap<>(4); map.put(9,3); map.put(7,4); map.put(5,9); map.put(3,4); map.put(6,6); //總共put了5個元素,超過了指定的快取最大容量 //遍歷結果 for(Iterator<Map.Entry<Integer,Integer>> it=map.entrySet().iterator();it.hasNext();){ System.out.println(it.next().getKey()); } } }
9=3
9=3
9=3
9=3
7
5
3
6 分析一下:使用帶引數構造器,且啟用LRU模式的LinkedHashMap會在每次有新元素加入的時候,判斷當前儲存元素是否超過了快取上限,也就是執行 一次removeEldestEntry方法,看最後的遍歷結果,發現果然把9刪除了,LRU發揮作用了~