手撸LRU算法

# 算法思路

LRU 算法的淘汰策略是 Least Recently Used,也就是每次淘汰那些最久没被使用的数据

LRU 算法的核心数据结构是使用哈希表和链表,首先借助链表的有序性使得链表元素维持插入顺序,同时借助哈希映射的快速访问能力使得我们可以在 O(1) 时间访问链表的任意元素。

  1. LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  2. void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

# 代码实现

先实现NodeDoubleList,再实现LURCache中的抽象方法makeRecentlydeleteKeyaddRecentlyremoveLeastRecently

class LRUCache {
    private HashMap<Integer,Node> map;
    private DoubleList cache;
    private int cap;
    public LRUCache(int capacity) {
        cap = capacity;
        map = new HashMap<>();
        cache = new DoubleList();
    }

    public void makeRecently(int key){
        // 先删除再添加到尾部
        Node x = map.get(key);
        cache.remove(x);
        cache.addLast(x);
    }

    public void deleteKey(int key){
        Node x = map.get(key);
        cache.remove(x);
        map.remove(key);
    }

    public void addRecently(int key, int val){
        // 直接添加到尾部
        Node x = new Node(key,val);
        cache.addLast(x);
        map.put(key, x);
    }

    public void removeLeastRecently(){
        Node x = cache.removeFirst();
        map.remove(x.key);
    }
    
    public int get(int key) {
        if(!map.containsKey(key)){
            return -1;
        }
        makeRecently(key);
        return map.get(key).val;
    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)){
            deleteKey(key);
            addRecently(key, value);
        } else {
            if(map.size() == cap){
                removeLeastRecently();
            }
            addRecently(key, value);
        }


    }
}

class Node {
    public int key;
    public int val;
    public Node next;
    public Node prev;
    public Node(int k, int v){
        key = k;
        val = v;
    }
}

class DoubleList {
    private int size;
    private Node head;
    private Node tail;

    public DoubleList(){
        head = new Node(0,0);
        tail = new Node(0,0);
        head.next = tail;
        tail.prev = head;
    }

    public void addLast(Node x){
        x.prev = tail.prev;
        x.next = tail;
        tail.prev.next = x;
        tail.prev = x;
        size++;
    }

    public void remove(Node x){
        x.prev.next = x.next;
        x.next.prev = x.prev;
        size--;
    }

    // 删除First其实是删除leastRecentlyNode
    public Node removeFirst(){
        if(head.next == tail){
            return null;
        }
        Node first = head.next;
        remove(first);
        return first;
    }

    public int size(){
        return size;
    }
}