实现LRU算法的两种方法

一、LinkedHashMap

LinkedHashMap 内部维护了一个双向链表,用来维护插入顺序或者 LRU(最近最久未使用)顺序。

其中有一个属性——accessOrder,当一个节点被访问时,如果 accessOrder 为 true,则会将该节点移到链表尾部。也就是说指定为 LRU 顺序之后,在每次访问一个节点时,会将这个节点移到链表尾部,保证链表尾部是最近访问的节点,那么链表首部就是最近最久未使用的节点。

在 put 等操作之后执行,当 removeEldestEntry()方法返回 true 时(即 size > threshold)会移除最晚的结点,即链表的首部结点。

以下是使用 LinkedHashMap 实现的一个 LRU 缓存:

  • 设定最大缓存空间 threshold 为4;
  • 使用 LinkedHashMap 的构造函数将 accessOrder 设置为 true,开 LRU 顺序;
  • 覆盖 removeEldestEntry()方法实现,在结点多于 threshold 时就会将最近最久未使用的数据移除。
public class LRU extends LinkedHashMap {
    private int initialSize;
    public LRU(int initialSize) {
        super(initialSize, 0.75f, true);
        this.initialSize = initialSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return this.size() > initialSize;
    }

    public String toString() {
        StringBuilder cacheStr = new StringBuilder();
        cacheStr.append("{");

        for (Map.Entry entry : this.entrySet()) {
            cacheStr.append("[" + entry.getKey() + "," + entry.getValue() + "]");
        }
        cacheStr.append("}");
        return cacheStr.toString();
    }

    public static void main(String[] args) {
        LRU cache = new LRU<>(3);
        cache.put(1, 111);
        cache.put(2, 222);
        cache.put(3, 333);
        cache.get(2);
        cache.put(4, 444);
        System.out.println(cache.toString());
    }
}

二、双向链表 + HashMap

public class LRU {
    static HashMap map = new HashMap<>();
    static Node head = new Node();
    static Node end = null;
    static int capacity = 4;
    public static void tranverse() { // 遍历链表
        Node phead = head.next;
        while (phead != null) {
            System.out.print("(" + phead.key + "," + phead.value + ")->");
            phead = phead.next;
        }
        System.out.println();
    }
    public static int get(int key) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            remove(node);
            setHead(node); // 访问结点时,将其置为头结点
            return node.value;
        }
        return -1;
    }
    public static void remove(Node node) {
        if (null == node.next) {
            node.pre.next = null;
        } else {
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }

    }
    public static void setHead(Node node) {
        if (head.next != null) {
            node.next = head.next;
            head.next.pre = node;
            head.next = node;
            node.pre = head;
        } else {
            head.next = node;
            node.pre = head;
        }
    }
    public static void put(int key, int value) {
        if (map.containsKey(key)) {
            Node old = map.get(key);
            old.value = value;
            remove(old);
            setHead(old);
        } else {
            Node newCode = new Node(key, value);
            map.put(key, newCode);
            if (head.next != null) { // 找到end所在结点
                end = head.next;
                while (end.next != null) {
                    end = end.next;
                }
            }
            if (map.size() > capacity) // 当size >= capacity时移除end结点
                if (end.key != -1) {
                    map.remove(end.key);
                    remove(end);
                    setHead(newCode);
                } else {
                    setHead(newCode);
                }
            } else {
                setHead(newCode);
            }
        }
    }
}
class Node { // 双向链表
    int key = -1;
    int value = -1;
    Node pre = null;
    Node next = null;
    public Node() {

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

 

你可能感兴趣的:(coding)