zoukankan      html  css  js  c++  java
  • 【力扣】146. LRU缓存机制

    运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

    获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
    写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

    进阶:

    你是否可以在 O(1) 时间复杂度内完成这两种操作?

    示例:

    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

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/lru-cache

    class LRUCache {
    
    //LRU 缓存机制可以通过哈希表辅以双向链表实现,我们用一个哈希表和一个双向链表维护所有在缓存中的键值对。
        private static class Node{
            private int key;
    
            private int value;
    
            private Node prev; //前置结点
    
            private Node next; //下一个节点
    
            public Node(){}
    
            public Node(int key,int value){
                this.key = key;
                this.value = value;
            }
    
        }
    
        //当容量满的时候,采用LRU淘汰策略
        //1.淘汰最少使用的数据
        //2.淘汰最早放进来的数据
    
        private Map<Integer,Node> map = new HashMap<Integer,Node>();
    
        //标识容量 是一个固定值
        private int capacity;
    
        //标识大小,当前大小
        private int size;
    
        //头结点
        private Node head;
    
        //尾节点
        private Node tail;
    
    
        public LRUCache(int capacity) {
            this.capacity = capacity;
            this.size = 0;
            // 使用伪头部和伪尾部节点
            head = new Node();
            tail = new Node();
            head.next = tail;
            tail.prev = head;
        }
        
        //如果 key 不存在,则返回 -1−1;
        //如果 key 存在,则 key 对应的节点是最近被使用的节点。通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部,最后返回该节点的值
        public int get(int key) {
            Node  result = map.get(key);
            if(result == null){
                return -1;
            }
            //通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部
            result.prev.next = result.next;
            result.next.prev = result.prev;
                //把当前节点放到头结点
                result.prev = head;
                result.next = head.next;
                head.next.prev = result;
                head.next = result;
            return result.value;
        }
        
        /**
        对于 put 操作,首先判断 key 是否存在:
        如果 key 不存在,使用 key 和 value 创建一个新的节点,在双向链表的头部添加该节点,并将 key 和该节点添加进哈希表中。然后判断双向链表的节点数是否超出容量,如果超出容量,则删除双向链表的尾部节点,并删除哈希表中对应的项;
        如果 key 存在,则与 get 操作类似,先通过哈希表定位,再将对应的节点的值更新为 value,并将该节点移到双向链表的头部。
        **/
        public void put(int key, int value) {
            Node  result = map.get(key);
            //若是没有则放入新的node节点
            if(result == null){
                Node node = new Node(key,value);
                //添加到hash表
                map.put(key,node);
                //把新加入的节点放到链表的头部
                node.prev = head;
                node.next = head.next;
                head.next.prev = node;
                head.next = node;
                ++size;
                //如果当前大小已经超出了容量,就把最久未使用的删除
                if(size > capacity){
                    //去除hash表中的值
                    map.remove(tail.prev.key);
                    //去除链表中最久未使用的节点
                    tail.prev.prev.next = tail;
                    tail.prev = tail.prev.prev;
                    --size;
                }
            } else {
                //若是有值,需要把原来的值覆盖
                result.value = value;
                map.put(key,result);
    
                //把链表中的节点放到头结点
                //先把当前节点删除
                result.prev.next = result.next;
                result.next.prev = result.prev;
    
                //把当前节点放到头结点
                result.prev = head;
                result.next = head.next;
                head.next.prev = result;
                head.next = result;
            }
        }
    }
    
    /**
     * Your LRUCache object will be instantiated and called as such:
     * LRUCache obj = new LRUCache(capacity);
     * int param_1 = obj.get(key);
     * obj.put(key,value);
     */
    一个入行不久的Java开发,越学习越感觉知识太多,自身了解太少,只能不断追寻
  • 相关阅读:
    论有一个服务器后可以干什么
    golang的安装后的文件目录解析
    使用go自带的http包搭建一个的web服务器
    python字符串问题—文件排版
    Python 整数的N进制字符串表示,循环和函数_亲密数,DNA匹配A
    mongodb 基本CRUD
    pip;python包管理工具
    STM32中assert_param的使用
    stm32.cube(一)——系统架构及目录结构
    HTTP、TCP、UDP,Socket,HTTPS
  • 原文地址:https://www.cnblogs.com/fengtingxin/p/13890720.html
Copyright © 2011-2022 走看看