LRU

LRU是一种缓存淘汰策略,全称是Least Recently Used,即最近最少使用,也就是说我们认为最近使用过的数据应该是是有用的,很久都没用过的数据应该是无用的。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。

LRU的实现思路就是hashmap+双链表,其中hashmap是为了加速查询, 双链表是为了保存使用状态,当一个缓存项被get, 这个缓存项会被移动到双向链表的头部。 当存储的缓存项超过了指定的capacity,则会从双链表的尾部进行移除。
Java已经自带了这种数据结构

 1 package test1;
 2 
 3 import java.util.LinkedHashMap;
 4 import java.util.Map;
 5 
 6 public class LRUCache {
 7 
 8     private LinkedHashMap<Integer, Integer> map;
 9     private final int CAPACITY;
10 
11     public LRUCache(int capacity) {
12         CAPACITY = capacity;
13         map = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {
14             @Override
15             protected boolean removeEldestEntry(Map.Entry eldest) {
16                 return size() > CAPACITY;
17             }
18         };
19     }
20 
21     public int get(int key) {
22         return map.getOrDefault(key, -1);
23     }
24 
25     public void put(int key, int value) {
26         map.put(key, value);
27     }
28 }
package test1;

import java.util.HashMap;
import java.util.Map;

public class MyLru<K, V> {

    private int capacity;
    private Node head;
    private Node tail;
    private Map<K, Node> map;

    public MyLru(int capacity) {
        this.capacity = capacity;
        this.map = new HashMap<>(8);
    }

    public void put(K k, V v) {
        // 如果链表为空
        if (head == null) {
            head = new Node(k, v);
            tail = head;
            map.put(k, head);
            return;
        }
        Node node = map.get(k);
        // 如果存在,则提到链表开始, 并更新值
        if (node != null) {
            node.value = v;
            removeToHead(node);
        } else {
            // 否则新建一个节点到开始
            Node newNode = new Node(k, v);
            // 如果长度到了容量,需要去除结尾的节点
            if (map.size() >= capacity) {
                System.out.println("移除末尾节点:[" + tail.key + "," + tail.value + "]");
                map.remove(tail.key);
                tail = tail.prev;
                tail.next = null;
            }
            // 连到开始
            map.put(k, newNode);
            head.prev = newNode;
            newNode.next = head;
            head = newNode;
        }
    }

    /**
     * 访问时,如果缓存有,则返回并把该节点放到最前面
     */
    public V get(K key) {
        Node node = map.get(key);
        if (node == null) {
            return null;
        }
        removeToHead(node);
        return node.value;
    }

    private void removeToHead(Node node) {
        if (node == head) {
            return;
        } else if (node == tail) {
            tail = node.prev;
            tail.next = null;
        } else {
            node.prev.next = node.next;
            node.next.prev = node.prev;
        }
        // set node to head
        node.next = head;
        head.prev = node;
        node.prev = null;
        head = node;
    }

    class Node {

        Node prev;
        Node next;
        K key;
        V value;

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }
}

参考

https://jimolonely.github.io/2019/05/31/algorithm/003-lru-java/

原文地址:https://www.cnblogs.com/beyondbit/p/13222194.html