栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

算法---Lru缓存(Java)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

算法---Lru缓存(Java)

题目:

设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。

它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

示例:

LRUCache cache = new LRUCache( 2 );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4

有问题的:
    class LRUCache {
        linkedHashMap map;
        int capacity;
        public LRUCache(int capacity) {
            map = new linkedHashMap(capacity, 0.75f,true);
            this.capacity = capacity;
        }

        public int get(int key) {
            if (map.containsKey(key)){
                return map.get(key);
            }
            return -1;
        }

        public void put(int key, int value) {
            if (map.size() == capacity) {
                Set> entries = map.entrySet();
                Iterator> iterator = entries.iterator();
                Map.Entry next = null;
                if (iterator.hasNext()) {
                    next = iterator.next();
                }

                if (next != null) {
                    map.remove(next.getKey());
                }
            }
            map.put(key,value);
        }
    }

发现自己的put 没有去检索当前map 里面是不是包含同样的key,这样的话,就不需要remove 掉一个元素。第二,发现自己对removeEldestEntry 方法不熟悉。

正确解决方法一:(偷懒)
class LRUCache extends linkedHashMap{
    private int capacity;
    
    public LRUCache(int capacity) {
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        super.put(key, value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > capacity; 
    }
}

方法二:
    class LRUCache {
        class Node{
            public Node pre;
            public Node nex;
            public int value;
            public Node(int value){
                this.value = value;
            }
        }
        //
        Map map ;
        Node head,tail;
        int capacity;

        public LRUCache(int capacity) {
            map = new HashMap(capacity);
            head = new Node(-1);
            tail = new Node(-1);
            head.nex = tail;
            tail.pre = head;
            this.capacity = capacity;
        }

        public int get(int key) {
            // have
            if (map.containsKey(key)) {
                // find key
                Node node = findKey(key);
                //move to head
                moveToFirst(node);
                //get value
                return (int) map.get(key);
            }else {
                // not contains return -1
                return -1;
            }
        }

        public void put(int key, int value) {
            if (map.containsKey(key)) {
                //find
                Node node = findKey(key);
                // to head
                moveToFirst(node);
                map.put(key,value);
            }else {
                if (map.size() > capacity) {
                    //remove last
                    Node pre = tail.pre;
                    Node node = pre.pre;
                    node.nex = tail;
                    tail.pre = node;
                    // put new
                    putNew(key, value);
                    map.remove(pre.value);
                }else {
                    putNew(key, value);
                }
            }
        }

        private void putNew(int key, int value) {
            // put new
            Node node = new Node(key);
            map.put(key, value);
            //move to head
            moveToFirst(node);
        }


        public Node findKey(int key){
            // find key
            Node cur = head.nex;
            //linkedHashMap 也这样查找吗?
            while (cur != null) {
                if (cur.value == key) {
                    return cur;
                }
                cur = cur.nex;
            }
            return null;
        }

        public void moveToFirst(Node node){

            //if  is head
            if (head.nex == node) {
                return;
            }

            // 衔接node
            if (node.pre != null){
                Node pre1 = node.pre;
                Node nex1 = node.nex;
                pre1.nex = nex1;
                nex1.pre = pre1;
            }
            Node pre = head.nex;
            head.nex = node;
            node.pre = head;
            node.nex = pre;
            pre.pre = node;
        }
    }

有点乱 写了一个小时才写出来
不好的地方在于 hasMap 的value 应该放Node
这样就不需要findKey

建议参考:
public class LRUCache {
    class DlinkedNode {
        int key;
        int value;
        DlinkedNode prev;
        DlinkedNode next;
        public DlinkedNode() {}
        public DlinkedNode(int _key, int _value) {key = _key; value = _value;}
    }

    private Map cache = new HashMap();
    private int size;
    private int capacity;
    private DlinkedNode head, tail;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        // 使用伪头部和伪尾部节点
        head = new DlinkedNode();
        tail = new DlinkedNode();
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        DlinkedNode node = cache.get(key);
        if (node == null) {
            return -1;
        }
        // 如果 key 存在,先通过哈希表定位,再移到头部
        moveToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        DlinkedNode node = cache.get(key);
        if (node == null) {
            // 如果 key 不存在,创建一个新的节点
            DlinkedNode newNode = new DlinkedNode(key, value);
            // 添加进哈希表
            cache.put(key, newNode);
            // 添加至双向链表的头部
            addToHead(newNode);
            ++size;
            if (size > capacity) {
                // 如果超出容量,删除双向链表的尾部节点
                DlinkedNode tail = removeTail();
                // 删除哈希表中对应的项
                cache.remove(tail.key);
                --size;
            }
        }
        else {
            // 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(DlinkedNode node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(DlinkedNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void moveToHead(DlinkedNode node) {
        removeNode(node);
        addToHead(node);
    }

    private DlinkedNode removeTail() {
        DlinkedNode res = tail.prev;
        removeNode(res);
        return res;
    }
}

思考:

1.写算法应该先写逻辑
// fink key
//return value
//…
保证每一步骤都不能少
比如此题
如果超过了容量
要从map里面remove 掉
不然就会有问题

2.写的每一行代码 写完要思考一下对不对
比如 >= 写成了> 结果可能就错了
你在每一行都思考一下
出了错误页不需要整个篇幅去排查问题了

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/777972.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号