LRU算法

发布时间 2023-08-28 18:22:13作者: kiper

思路

LRU算法,访问/更新/插入都会将数据置于队尾(假设队头淘汰)。

看3种情况的变化:

  • 插入:简单置于队尾即可。
  • 更新:删除原有节点,新增节点置于队尾。
  • 访问:将原节点提至队尾。

除了插入只需要简单接到链表尾部以外,更新和访问都是可能操作链表中间的,所以自然地就需要引入Map来快速找到对应节点。
并且无论是更新的删除原有节点还是访问的将原节点提至队尾,都需要在链表中间删除节点,所以需要双向链表。

首先实现Node类及DoubleList类,然后按照LRU算法思路实现即可。

代码

原始代码

class LRUCache {

    private int capacity;

    private DoubleList list;

    private Map<Integer, Node> map;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        list = new DoubleList();
        map = new HashMap<>();
    }
    
    public int get(int key) {
        if (!map.containsKey(key)) return -1;
        Node node = map.get(key);
        list.remove(node);
        list.addLast(node);
        return node.val;
    }
    
    public void put(int key, int value) {
         Node node = new Node(key, value);
        // key不存在
        if (!map.containsKey(key)) {
            // 链表大小 == 容量
            if (list.size() == capacity) {
                Node first = list.removeFirst();
                int firstkey = first.key;
                map.remove(first.key);
                int listsize = list.size();
                int mapsize = map.size();
                int a = key;
            }
            map.put(key, node);
            list.addLast(node);
            return;
        } 
        // key存在
        Node oldNode = map.get(key);
        list.remove(oldNode);
        map.put(key, node);
        list.addLast(node);
    }

}

class DoubleList {
    
    private Node head, tail;

    private int size;

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

    public void addLast(Node node) {
        node.pre = tail.pre;
        node.next = tail;
        tail.pre.next = node;
        tail.pre = node;
        size++;
    }
        
    public void remove(Node node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
        size--;
    }

    public Node removeFirst() {
        if (head.next == tail)
            return null;
        Node first = head.next;
        remove(first);
        return first;
    }

    public int size() {
        return size;
    }

}

class Node {

    // key为了方便移出双向链表后,再去删除Map中的键值对
    int key;

    int val;

    Node pre;

    Node next;

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

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

优化代码