Java实现自定义LRU算法

发布时间 2023-04-10 23:24:27作者: zhaozihang
class LRUCache {
    // key -> Node<key,val>
    private HashMap<Integer, Node> map;
    // Node(k1,v1) <-> Node(k2,v2)
    private DoubleList cache;
    // 最大容量
    private int cap;

    public LRUCache(int capacity) {
        this.cap = capacity;
        map = new HashMap<>();
        cache = new DoubleList();
    }   
    
    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);
            return;
        }
        
        if(cap == cache.size()){
            // 删除最久未使用的元素
            removeLeastRecently();
        }
        //添加新元素为最近使用的元素
        addRecently(key, value);
    }

    // 将某个key提升为最近使用的
    private void makeRecently(int key){
        Node x = map.get(key);
        // 先从链表中删除这个节点
        cache.remove(x);
        //重新插到队尾
        cache.addLast(x);
    }

    // 添加最近使用的元素
    private void addRecently(int key, int val){
        Node x = new Node(key, val);
        // 链表尾部就是最近使用的元素
        cache.addLast(x);
        //在map中添加key的映射
        map.put(key, x);
    }

    // 删除某一个key
    private void deleteKey(int key){
        Node x = map.get(key);
        // 从链表中删除
        cache.remove(x);
        // 从map中删除
        map.remove(key);
    }

    // 删除最久未使用的元素
    private void removeLeastRecently(){
        // 链表头部的第一个元素就是最久未使用的
        Node deleteNode = cache.removeFirst();
        // 删除map中的映射
        int deletedKey = deleteNode.key;
        map.remove(deletedKey);
    }
}

// 定义双向链表的节点
// 默认 key和value为int类型
class Node{
    public int key,val;
    public Node next,prev;
    public Node(int k, int v){
        this.key = k;
        this.val = v;
    }
}

// 构建一个双向链表
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.prev = head;
        size = 0;
    }

    // 在链表尾部添加节点x,时间为O(1)
    public void addLast(Node x){
        x.prev = tail.prev;
        x.next = tail;
        tail.prev.next = x;
        tail.prev = x;
        size++;
    }

    // 删除链表中的x节点(x一定存在)
    // 由于是双链表且给的是目标Node节点,时间为O(1)
    public void remove(Node x){
        x.prev.next = x.next;
        x.next.prev = x.prev;
        size--;
    }

    //删除链表中第一个节点,并返回该节点,时间O(1)
    public Node removeFirst(){
        if(head.next == null){
            return null;
        }
        Node first = head.next;
        remove(first);
        return first;
    }

    // 返回链表的长度,时间O(1)
    public int size(){
        return size;
    }
}