zoukankan      html  css  js  c++  java
  • 146_LRU cache | LRU缓存设计

     

    题目:

    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.

    题解:

    这道题是一个数据结构设计题,在leetcode里面就这么一道,还是挺经典的一道题,可以好好看看。

    这道题要求设计实现LRU cache的数据结构,实现set和get功能。学习过操作系统的都应该知道,cache作为缓存可以帮助快速存取数据,但是确定是容量较小。这道题要求实现的cache类型是LRU,LRU的基本思想就是“最近用到的数据被重用的概率比较早用到的大的多”,是一种更加高效的cache类型。

    解决这道题的方法是:双向链表+HashMap

    “为了能够快速删除最久没有访问的数据项和插入最新的数据项,我们将双向链表连接Cache中的数据项,并且保证链表维持数据项从最近访问到最旧访问的顺序。 每次数据项被查询到时,都将此数据项移动到链表头部(O(1)的时间复杂度)。这样,在进行过多次查找操作后,最近被使用过的内容就向链表的头移动,而没 有被使用的内容就向链表的后面移动。当需要替换时,链表最后的位置就是最近最少被使用的数据项,我们只需要将最新的数据项放在链表头部,当Cache满 时,淘汰链表最后的位置就是了。 ”

     “注: 对于双向链表的使用,基于两个考虑。

                首先是Cache中块的命中可能是随机的,和Load进来的顺序无关。

             其次,双向链表插入、删除很快,可以灵活的调整相互间的次序,时间复杂度为O(1)。”

    解决了LRU的特性,现在考虑下算法的时间复杂度。为了能减少整个数据结构的时间复杂度,就要减少查找的时间复杂度,所以这里利用HashMap来做,这样时间苏咋读就是O(1)。

     所以对于本题来说:

    get(key): 如果cache中不存在要get的值,返回-1;如果cache中存在要找的值,返回其值并将其在原链表中删除,然后将其作为头结点。

    set(key,value):当要set的key值已经存在,就更新其value, 将其在原链表中删除,然后将其作为头结点;当药set的key值不存在,就新建一个node,如果当前len<capacity,就将其加入hashmap中,并将其作为头结点,更新len长度,否则,删除链表最后一个node,再将其放入hashmap并作为头结点,但len不更新。

     

    原则就是:对链表有访问,就要更新链表顺序。 

    代码如下:

     1 public class LRUCache {
     2     private HashMap<Integer, DoubleLinkedListNode> map
     3             = new HashMap<Integer, DoubleLinkedListNode>();
     4     private DoubleLinkedListNode head;
     5     private DoubleLinkedListNode end;
     6     private int capacity;
     7     private int len;
     8 
     9     public LRUCache(int capacity) {
    10         this.capacity = capacity;
    11         len = 0;
    12     }
    13 
    14     public int get(int key) {
    15         if (map.containsKey(key)) {
    16             DoubleLinkedListNode latest = map.get(key);
    17             removeNode(latest);
    18             setHead(latest);
    19             return latest.val;
    20         } else {
    21             return -1;
    22         }
    23     }
    24 
    25     public void removeNode(DoubleLinkedListNode node) {
    26         DoubleLinkedListNode cur = node;
    27         DoubleLinkedListNode pre = cur.pre;
    28         DoubleLinkedListNode post = cur.next;
    29 
    30         if (pre != null) {
    31             pre.next = post;
    32         } else {
    33             head = post;
    34         }
    35 
    36         if (post != null) {
    37             post.pre = pre;
    38         } else {
    39             end = pre;
    40         }
    41     }
    42 
    43     public void setHead(DoubleLinkedListNode node) {
    44         node.next = head;
    45         node.pre = null;
    46         if (head != null) {
    47             head.pre = node;
    48         }
    49 
    50         head = node;
    51         if (end == null) {
    52             end = node;
    53         }
    54     }
    55 
    56     public void set(int key, int value) {
    57         if (map.containsKey(key)) {
    58             DoubleLinkedListNode oldNode = map.get(key);
    59             oldNode.val = value;
    60             removeNode(oldNode);
    61             setHead(oldNode);
    62         } else {
    63             DoubleLinkedListNode newNode =
    64                     new DoubleLinkedListNode(key, value);
    65             if (len < capacity) {
    66                 setHead(newNode);
    67                 map.put(key, newNode);
    68                 len++;
    69             } else {
    70                 map.remove(end.key);
    71                 end = end.pre;
    72                 if (end != null) {
    73                     end.next = null;
    74                 }
    75 
    76                 setHead(newNode);
    77                 map.put(key, newNode);
    78             }
    79         }
    80     }
    81 }
    82 
    83 class DoubleLinkedListNode {
    84     public int val;
    85     public int key;
    86     public DoubleLinkedListNode pre;
    87     public DoubleLinkedListNode next;
    88 
    89     public DoubleLinkedListNode(int key, int value) {
    90         val = value;
    91         this.key = key;
    92     }
    93 }
  • 相关阅读:
    字符编码相关
    函数之形参与实参
    文件操作模式
    函数对象,名称空间,作用域,和闭包
    吴裕雄天生自然SPRINGBOOT开发实战处理'spring.datasource.url' is not specified and no embedded datasource could be autoconfigured
    吴裕雄天生自然SPRINGBOOT开发实战处理XXXX that could not be found.
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot HTML表单登录
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot REST示例
    吴裕雄天生自然SpringBoot开发实战学习笔记处理 Could not write metadata for '/Servers'.metadata\.plugins\org.eclipse.core.resources\.projects\Servers\.markers.snap (系统找不到指定的路径。)
    吴裕雄天生自然SPRINGBOOT开发实战SpringBoot Tomcat部署
  • 原文地址:https://www.cnblogs.com/wzj4858/p/10394464.html
Copyright © 2011-2022 走看看