兩種方法手寫LRU(LinkedHashMap&&map+雙鏈表)

前面註釋掉的部分是簡單的用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");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章