前面註釋掉的部分是簡單的用LinkedHashMap寫的LRU,屬於沒有技術含量,也不能很好的理解LRU.
import java.util.HashMap;
/**
* @ClassName LRU 藉助LinkedHashMap,重寫removeEldestEntry,調用LinkedHashMap的size()方法來判斷存入的元素個數。
* @Description TODO
* @Author Handoking
* @Date 2019/7/17 8:54
**/
//public class LRU<K,V> extends LinkedHashMap<K,V> {
// int size =5;
// public LRU(int size){
// super(16,0.75f,true);
// this.size = size;
// }
//
// @Override
// protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
// return size()>size;
// }
//}
/**
* @ClassName LRU 使用map和雙鏈表實現。
* @Description TODO
* @Author Handoking
* @Date 2019/7/17 8:54
**/
public class LRU<K,V>{
class CacheNode {
CacheNode pre;
CacheNode next;
Object key;
Object value;
CacheNode(Object key, Object value) {
this.key = key;
this.value = value;
this.pre = null;
this.next =null;
}
CacheNode(){
}
}
private int cacheSize;
private HashMap<K,CacheNode> cache;
private CacheNode head;
private CacheNode tail;
public LRU(int size){
this.cacheSize = size;
cache = new HashMap<>();
}
public Object put(K k,V v){
CacheNode node = cache.get(k);
Object temp=-11111;
if(node==null){
//當前節點不存在,判斷緩存是否已經存滿,若存滿,那麼刪除尾節點,同時刪除map中存儲的數據。
if(cache.size()>=cacheSize){
cache.remove(tail.key);
delectTail();
}
//創建新結點
node =new CacheNode();
node.key = k;
}else{
temp = node.value;
}
//無論存在不存在,都需要將此節點移動到鏈表頭,因此統一合併操作。
node.value = v;
cache.put(k,node);
moveToHead(node);
//返回舊值
if(!temp.equals(-11111)){
return temp;
}
return -1;
}
public Object get(K k){
//get的操作需要判斷,如果結點存在那麼返回值並將此節點移動到鏈表頭部
//如果不存在,返回空值
CacheNode node = cache.get(k);
if(node==null){
return null;
}
moveToHead(node);
return node.value;
}
private void delectTail(){
if(tail!=null){
tail = tail.pre;
if (tail==null){
//此時tail爲空值時,說明頭節點和尾節點爲同一節點,刪除後整個鏈表爲空
head=null;
}else{
tail.next =null;
}
}
}
private void moveToHead(CacheNode node){
//如果是頭節點,那麼不需要操作
if(node==head){
return;
}
//如果不是頭節點,
if (node==tail){
tail = tail.pre;
tail.next=null;
}
if(node.next!=null){
node.next.pre = node.pre;
}
if(node.pre!=null){
node.pre.next = node.next;
}
//至關重要,如果是首次插入,那麼head爲空
if(head==null||tail==null){
head=tail =node;
return;
}
node.next = head;
head.pre = node;
head =node;
head.pre = null;
}
public Object remove(K k){
//如果值存在,鏈表中調整前後的指針刪除節點,cache中使用map直接刪除
CacheNode node = cache.get(k);
if (node!=null){
if(node==head){
head =node.next;
head.pre =null;
}
if(node ==tail){
tail = node.pre;
tail.next=null;
}
if(node.pre!=null){
node.pre.next = node.next;
}
if (node.next!=null) {
node.next.pre = node.pre;
}
}
//hashMap的remove方法會值在不存在時,返回空值,存在時返回被刪除的值,因此可以合併到這裏一併刪除緩存裏的值
return cache.remove(k);
}
public void clear(){
//鏈表清空,map清空
head =null;
tail =null;
cache.clear();
}
//測試
public static void main(String[] args) {
LRU<Integer,String> lru = new LRU<>(3);
lru.put(1, "a");
lru.put(2, "b");
lru.put(3, "c");
lru.get(1);
lru.put(4, "d");
System.out.println( lru.put(1, "aa"));
lru.put(2, "bb");
lru.put(5, "e");
lru.get(1);
System.out.println(lru.remove(11));
lru.remove(1);
lru.put(1, "aaa");
}
}