Java实现LRU缓存算法

53 阅读1分钟

最近最少使用页面置换算法

LRU流程大概如此 image.png

流程图有点抽象,举个例子 1698715181242.png 总结(元素访问)

  1. 当容器充足且不冲突时,添加到头部,所有元素顺延
  2. 当容器充足但冲突时,将元素移动到头部
  3. 当容器不充足时,移除尾部,将元素添加到头部

有了以上简单工作原理后就可以写程序了 方法一:利用轮子(LinkedList)模拟双向队列+hashMap实现 特点:空间复杂度有点高,时间复杂度也高

image.png

public class LRUCache {
    Map<Integer,Integer>map;
    LinkedList<Integer>list;
    int capacity;
    public LRUCache(int capacity) {
        this.capacity=capacity;
        map=new HashMap<>();
        list=new LinkedList<>();
    }

    public int get(int key) {
        if (map.containsKey(key)){
            list.removeIf(new Predicate<Integer>() {
                @Override
                public boolean test(Integer integer) {
                    return integer==key;
                }
            });
            list.addFirst(key);
            return key;
        }
        return -1;

    }

    public void put(int key, int value) {
        if (map.containsKey(key)){
            list.removeIf(new Predicate<Integer>() {
                @Override
                public boolean test(Integer integer) {
                    return integer==key;
                }
            });
        }else {
            if (map.size()==capacity){
                int last = list.getLast();
                map.remove(last);
                list.removeLast();
            }
        }
        map.put(key,value);
        list.addFirst(key);
    }
}

方法二:模拟双向队列+HashMap 空间复杂度降低了

image.png

Map<Integer,Node>map=new HashMap<>();
    Node head;
    Node tail;
    int capacity;
    public LRUCache(int capacity) {
        this.capacity=capacity;
        head=new Node();
        tail=new Node();
        head.next=tail;
        tail.pre=head;
    }

    public int get(int key) {
        if (!map.containsKey(key)){
            return -1;
        }
        Node node = map.get(key);
        moveToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        Node node = map.get(key);
        if (node!=null){
            node.value=value;
            moveToHead(node);
        }else {
            Node node1=new Node(key,value);
            map.put(key,node1);
            addToHead(node1);
            if (map.size()>capacity){
                Node node2 = removeTail();
                map.remove(node2.key);
            }
        }
    }

    private Node removeTail() {
        Node pre = tail.pre;
        remove(pre);
        return pre;
    }

    private void moveToHead(Node node) {
        remove(node);
        addToHead(node);
    }

    private void addToHead(Node node) {
        node.pre=head;
        head.next.pre=node;
        node.next=head.next;
        head.next=node;
    }

    private void remove(Node node) {
        node.pre.next=node.next;
        node.next.pre=node.pre;
    }

    public class Node{
        int key;
        int value;
        Node pre;
        Node next;

        public Node() {}

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