如何設計實現LRU緩存?且GET()和Set()的複雜度爲0(1)。算法
LRU 全稱Least Recently Used, 最近最少使用緩存。數組
若是一個數據在最近一段時間沒有被訪問到,那麼在未來它被訪問的可能性也很小 也就是說,當限定的空間已存滿 數據時,應當把最久沒有被訪問到的數據淘汰緩存
可能大多數人都會想到:用一個數組來存儲數據,給每個數據項標記一個訪問時間戳,每次插入新數據項的時 候,先把數組中存在的數據項的時間戳自增,並將新數據項的時間戳置爲0並插入到數組中。每次訪問數組中的數 據項的時候,將被訪問的數據項的時間戳置爲0。當數組空間已滿時,將時間戳最大的數據項淘汰。 這種實現思路 很簡單,可是有什麼缺陷呢?須要不停地維護數據項的訪問時間戳,另外,在插入數據、刪除數據以及訪問數據 時,時間複雜度都是O(n),數組的缺陷凸顯無疑markdown
那就是利用鏈表和HashMap。 當須要插入新數據項,在鏈表中命中,則把該節點移到鏈表頭部 不存在,則新建一個節點,放在鏈表頭部,若緩存滿,則把鏈表最後一個節點刪除便可。 在訪問數據時,若數據項在鏈表中存在,則把該節點移到鏈表頭部,不然返回-1 這樣一來在鏈表尾部的節點就是最近最久未訪問的數據項。數據結構
1)set(key,value) 若key在hashmap中存在,則先重置value,而後獲取對應節點cur,將其從鏈表刪除,並移到鏈表頭 不存在,則新 建一個節點,並將節點放到鏈表的頭部。 當Cache滿,刪除鏈表最後一個節點spa
2)get(key) 若key在hashmap中存在,把對應的節點放到鏈表頭,並返回對應value 若不存在,則返回-1 即保證基本的get/set 同時,還要保證最近訪問(get或put)的節點保持在限定容量的Cache中,若是超過容量則應該把LRU(近期最少使用) 的節點刪除掉。線程
當咱們在get/set一個節點時都會把操做的這個節點移動到tail節點處,表明最新操做的節點,head節點永遠指向最 老的節點,當超過設定的容量時,咱們就刪除head節點指向的最老節點 就像是個LinkedHashMap,這樣作的好處是,get/set在不衝突狀況下可保證O(1)複雜度 也可經過雙向鏈表保證 LRU的刪除/更新O(1)複雜度 固然可簡化head和tail變成一個head節點,成環,這樣head的next指向最舊的節點,prev指向最新的節點。設計
維護一個線程 惰性刪除code