Java实现LRU缓存机制

本文介绍了如何使用Java实现LRU(Least Recently Used)缓存机制,主要讲解了两种方法:一是利用LinkedHashMap,二是结合双链表和HashMap。在不允许使用LinkedHashMap的情况下,通过双链表维护数据的新旧顺序,利用HashMap进行快速查找,当缓存满时,采用头插法更新并删除最不常用的数据。

力扣链接

在这里插入图片描述
在这里插入图片描述

方法一:使用 LinkedHashMap

public class LRUCache{
    int capacity;
    Map<Integer, Integer> map;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        map = new LinkedHashMap<>();
    }

    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        // 先删除旧的位置,再放入新位置
        Integer value = map.remove(key);
        map.put(key, value);
        return value;
    }

    public void put(int key, int value) {
        if (map.containsKey(key)) {
            map.remove(key);
            map.put(key, value);
            return;
        }
        map.put(key, value);
        // 超出capacity,删除最久没用的,利用迭代器删除第一个
        if (map.size() > capacity) {
            map.remove(map.entrySet().iterator().next().getKey());
        }
    }
}

如果面试管要求不能使用LinkedHashMap,那么,

方法二:使用双链表+HashMap

  • 底层应该用链表,按照数据的新旧程度来排列,旧的在右边,新的在左边,新来一个加到头部(你可以想象自己从有往左画一条链表),删除是删尾,除了这两个操作,还有就是把一个数据从中间拿出来放头上(这个数组就很难做到)
  • 这里还有一个需求,就是要知道这个数据有没有存在于链表中,如果不在链表中,加到头即可,如果已经在链表中,就只要更细数据的位置,如何查找这个数据在不在呢,这就用哈希表。
  • 考虑删除操作,要把当前节点的前一个节点的指针的改变,获取它前一个节点,方便的数据结构就是 双向链表。

这里我采用头插法来解决:

在插入的时候,首先判断map里的值,是否放满了,如果没有,那么还需要判断该值是否在链表中存在,如果存在,先删除在重新插入,如果不存在,那么直接插入。如果map满了,也有两种情况,一种时候,插入的值存在,那么更新一下,先删除,在插到头里,如果不存在,那么就要先移除尾巴上最不常用的,然后再插入到头!

在get获取的时候,首先判断map里是否存在,不存在,返回-1,如果存在,更新当前节点,先删除,然后,再加入到头

在这里插入图片描述
在这里插入图片描述
然后根据map的大小,来进行插入,删除,和获取就好了

class LRUCache {
    class Node{
        public int key;
        public int val;
        public Node pre;
        public Node next;
        public Node(int key,int val){
            this.key = key;
            this.val = val;
        }
    }
    Map<Integer,Node> map = new HashMap<>();
    int x ;
    Node head = new Node(-1,-1);
    Node tail = new Node(-1,-1);
    public LRUCache(int capacity) {
        this.x = capacity;
        head.next = tail;
        tail.pre = head;
    }
    
    public int get(int key) {
        if(map.containsKey(key)){
            int sum = map.get(key).val;
            delete(key);
            add(key,sum);
            return sum;
        }
        return -1;
    }
    
    public void put(int key, int value) {
        if(map.size() < x){
            if(map.containsKey(key)){
                delete(key);
                add(key,value);
            }else{
                add(key,value);
            }
            
        }else{
            if(map.containsKey(key)){
                delete(key);
                add(key,value);
            }else{
                Node node = tail.pre;
                Node cur = node.pre;
                tail.pre = cur;
                cur.next = tail;
                map.remove(node.key);
                add(key,value);
            }
        }
    }

    public void delete(int key){
        Node cur = map.get(key);
        Node node2 = cur.next;
        Node node1 = cur.pre;
        node1.next = node2;
        node2.pre = node1;
        map.remove(key);
    }

    public void add(int key,int value){
        Node cur = head.next;
        Node node = new Node(key,value);
        head.next = node;
        node.pre = head;
        node.next = cur;
        cur.pre = node;
        map.put(key,node);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值