LRU Cach Java

本文探讨了如何设计并实现一种最少最近使用(LRU)缓存机制,该机制需支持get和set两种操作。文章介绍了使用自定义双向链表节点结合哈希映射来高效实现LRU缓存的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

作为一个题目看了好久才看懂的菜鸟,有必要在这里解释一下这道题的意思。
在set的时候,如果key已经存在,那么将原来的值替换为value,如果不存在,并且已经到达容量了,那么需要删除最久没有访问的一个元素,然后再加入新的元素。

看了key和value,第一想法是map,然后再加上附加要求,那么感觉使用linkedHashMap比较合适,每次查询或者更新元素的时候,将map中原来的元素删除,再加入新的元素;如果容量不够,删除第一个元素就行。
写完程序,提交,结果提示找不到linkedHashMap这个类。限制了对LinkedHashMap的使用。

于是又了第二个想法,用map存储key和value的关系。用linkedList存取key的顺序,当对当前key有操作时,将当前key在list中的位置移到最后。如果需要删除元素, 删除当前元素的第一个值即可。于是有了以下程序:

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

    public int get(int key) {
        if(map.containsKey(key)){
            Iterator<Integer> iterator=list.iterator();
            while(iterator.hasNext()){
                if(iterator.next()==key){
                    iterator.remove();
                    break;
                }
            }
            list.add(key);
            return map.get(key);
        }
        return -1;
    }
    public void set(int key, int value) {
        if(map.size()<capacity||map.containsKey(key))
            map.put(key, value);
        else {

            map.put(key, value);
        }
    }
}

其实在提交之前就知道这个程序的弊端,因为采用了linkedList,没法精准的得到当前key在list中的位置,所以需要从头开始找,时间复杂度比较高,提交代码以后,果然超时。

为了解决以上问题,看了下讨论区的内容,然后发现,一个思路类似的方法,自定义每个节点,节点保存key和value的值,使用map存取key和node的对应关系,很好的解决了上面程序存在的问题,程序如下:

    private class Node{
        int key;
        int value;
        Node next;
        Node pre;
        public Node(int key,int val){
            this.key=key;
            value=val;
            pre=null;
            next=null;
        }
    }
    // Doubly link list of type Node.
    private class DoublyLL{
        Node head;
        Node last;
        int capacity;
        int count;

        public DoublyLL(int c){
            capacity=c;
            count=0;
            head=new Node(0, 0);
            last=new Node(0, 0);
            head.next=last;
            last.pre=head;
        }
    }
    HashMap<Integer, Node> map;// The map will store a reference to the Node in
                                // DLL corresponding to each key.
    DoublyLL dll;
    public LRUCache(int capacity){
        dll=new DoublyLL(capacity);
        map=new HashMap<Integer,Node>();
    }

    public int get(int key){
        if(map.containsKey(key)){
            Node n=map.get(key);
            if(n.pre!=dll.head){
                detach(n);
                attach(n);
            }
            return n.value;
        }else {
            return -1;
        }
    }
    public void set(int key,int value){
        Node n;
        if(!map.containsKey(key)){
            n=new Node(key, value);
            if(dll.capacity!=dll.count)
                dll.count++;
            else {
                map.remove(dll.last.pre.key);
                detach(dll.last.pre);
            }
            attach(n);
            map.put(key, n);
        }else {
            n=map.get(key);
            n.value=value;
            detach(n);
            attach(n);
        }
    }
    private void attach(Node node) {
        node.pre = dll.head;
        node.next = dll.head.next;
        dll.head.next.pre = node;
        dll.head.next = node;

    }

    private void detach(Node node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值