算法:LRU(最近最少使用)
本文參考自小灰文章:https://mp.weixin.qq.com/s/B5xiVeW22ZumbI9KfrYJSg
LRU算法
什么是LRU算法
LRU算法又稱最近最少使用算法,它的基本思想是長期不被使用的數據,在未來被用到的幾率也不大,所以當新的數據進來時我們可以優先把這些數據替換掉。
在LRU算法中,使用了一種有趣的數據結構,稱為哈希鏈表。我們知道哈希表是由多個<Key,Value>對組成的,哈希鏈表是將這寫節點鏈接起來,每一個節點都有一個前驅結點和后驅節點,就像雙向鏈表中的節點一樣。哈希表擁有了固定的排列順序。
基於哈希鏈表的有序性,我們就可以把<Key,Value>按照最后的使用時間來排列。
LRU算法的基本思路
假設我們使用哈希鏈表來緩存用戶信息,目前緩存了4個用戶,用戶按照時間順序從鏈表右端插入:
情景一:當訪問用戶5時,由於哈希鏈表中沒有用戶5的數據,從數據庫中讀取出來插入到緩存中
情景二:擋訪問用戶2時,由於哈希鏈表中有用戶2的數據,我們把它掐斷,放到鏈表最右段
情景三:同情景二,這次訪問用戶4的數據
情景四:當用戶訪問用戶6,用戶6在緩存中沒有,需要插入到鏈表中,但此時鏈表長度已滿,我們把最左端的用戶刪掉,然后插入用戶6
說明:我們仔細回顧一下,當緩存命中時,我們就把它放到最右端,也就是說排在右邊的是最近被使用過的,那左邊的當然是相對較少被訪問過的,所以當緩存不命中的時候,我們就把最左邊的剔除掉,所以這里就體現了最近最少使用的原則。
LRU算法的基本實現
public class LRUCache{ private int limit; private HashMap<String,Node> hashMap; private Node head; private Node end; public LRUCache(int limit) { this.limit = limit; hashMap = new HashMap<String,Node>(); } public String get(String key){ Node node = hashMap.get(key); if(node ==null) return null; refreshNode(node); return node.value; } public void put(String key,String value){ Node node = hashMap.get(key); if(node == null){ if(hashMap.size()>=limit) { String oldKey = removeNode(head); hashMap.remove(oldKey); } node = new Node(key,value); addNode(node); hashMap.put(key,node) }else{ node.value = value; refreshNode(node); } } public void remove(String key){ Node node = hashMap.get(key); removeNode(node); hashMap.remove(key); } /** * 刷新剛被訪問的節點位置 */ private void refreshNode(Node node) { if(node == end) return; removeNode(node); addNode(node); } /** * 刪除節點 */ public String removeNode(Node node){ if(node == end) //刪除尾節點 end = end.pre; else if(node ==head) //刪除頭節點 head = head.next; else { //移除中間節點 node.pre.next = node.next; node.next.pre = node.pre; } return node.key; } /** * 尾部插入節點 */ public void addNode(Node node) { if(end!=null) { end.next = node; node.pre = end; node.next = null; } end = node; if(head == null) head = node; } }