LRU缓存机制实现

#简介

LRU缓存机制,全称Least Recently Used,字面意思就是最近最少使用,是一种缓存淘汰策略。换句话说,LRU机制就是认为最近使用的数据是有用的,很久没用过的数据是无用的,当内存满了就优先删除很久没有使用的数据

可以使用哈希链表或者自定义双端链表类+哈希表两种方法来实现LRU缓存机制。

它应该支持以下操作:获取数据get和 写入数据put

获取数据get(key):如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回-1。 写入数据put(key, value):如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

#基于LinkedHashMap实现LRU缓存机制
class LRUCache {
    Map<Integer, Integer> map;
    int capacity;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        map = new LinkedHashMap<>();
    }

    public int get(int key) {
        // 若key不存在返回-1
        if (!map.containsKey(key)) {
            return -1;
        }
        // 若key存在则获取key对应的val
        int val = map.get(key);
        // 更新位置
        put(key, val);
        return val;
    }

    public void put(int key, int val) {
        // 若缓存命中则先删除数据在重新放入以更新位置
        if (map.containsKey(key)) {
            map.remove(key);
            map.put(key, val);
        } else {
            // 若缓存未命中则先判断是否达到最大容量
            // 超出容量则删除最久没有使用的数据(利用迭代器删除第一个)
            if (capacity == map.size()) {
                map.remove(map.keySet().iterator().next());
            }
            // 删除完成后存放新数据
            map.put(key, val);
        }
    }
}
#基于DoubleList与HashMap实现LRU缓存机制

如果不使用LinkedHashMap,可以自己造轮子,自定义DoubleList类并结合HashMap实现与LinkedHashMap相同的功能。

class LRUCache {
    int capacity;
    DoubleList cache;
    Map<Integer, Node> map;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        cache = new DoubleList();
        map = new HashMap<>();
    }

    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        int val = map.get(key).val;
        put(key, val);
        return val;
    }

    public void put(int key, int val) {
        Node node = new Node(key, val);
        if (map.containsKey(key)) {
            cache.remove(map.get(key));
            cache.addFirst(node);
            map.put(key, node);
        } else {
            if (capacity == cache.size) {
                map.remove(cache.removeLast().key);
            }
            cache.addFirst(node);
            map.put(key, node);
        }
    }
}

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

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

    public void addFirst(Node node) {
        Node temp = head.next;
        node.next = temp;
        temp.prev = node;
        head.next = node;
        node.prev = head;
        size++;
    }

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

    public Node removeLast() {
        if (size == 0) {
            return null;
        }
        Node del = tail.prev;
        remove(del);
        return del;
    }
}

class Node {
    int key;
    int val;
    Node prev;
    Node next;

    public Node(int key, int val) {
        this.key = key;
        this.val = val;
    }
}