两种方法手写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");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章