zoukankan      html  css  js  c++  java
  • LeetCode-146:LRU缓存机制

    题目描述:

     解题分析:

    LRU是Least Recently Used,因此在插入元素时候,需要插到最前面;当达到capacity时候,需要把最后一个(即距离上次使用时间最长的那个元素)移除。因此LRU需要以下几个操作:

    1、能够添加元素,并且始终将新添加的元素移到缓存最前面;

    2、 在添加数据时候,如果缓存满了,需要将最后面的元素移除;

    3、查询时候,如果查询到缓存中的数据,返回数据值并将该数据移动到缓存的前面,如果没有查到数据,返回-1;

    实现方法:双向链表+哈希表

    双向链表作用:一方面通过链表,维护节点之间的顺序,另一方面,双向链表通过伪节点head和tail,可以很方便的将最新的元素插入缓存最前面,或者将最后一个元素移除。

    哈希表作用:可以在常数时间内get和put元素。

    具体代码:(在官方的基础上改的)

     1 import java.util.Hashtable; // Hashtable相对HashMap来说,是线程安全的
     2 public class LRUCache {
     3 
     4   class DLinkedNode { //构建双向链表
     5     int key;
     6     int value;
     7     DLinkedNode prev;
     8     DLinkedNode next;
     9   }
    10 
    11   private void addNode(DLinkedNode node) {  // 始终将添加的元素放在伪节点head的后面
    12     node.prev = head;
    13     node.next = head.next;
    14     head.next.prev = node;
    15     head.next = node;
    16   }
    17 
    18   private void removeNode(DLinkedNode node){  // 移除节点
    19     DLinkedNode prev = node.prev;
    20     DLinkedNode next = node.next;
    21     prev.next = next;
    22     next.prev = prev;
    23   }
    24 
    25   private void moveToHead(DLinkedNode node){  // 将节点移动到缓存的前面
    26     removeNode(node);
    27     addNode(node);
    28   }
    29 
    30   private DLinkedNode popTail() {  // 移除缓存最后面的节点
    31     DLinkedNode res = tail.prev;
    32     removeNode(res);
    33     return res;
    34   }
    35 
    36   private Hashtable<Integer, DLinkedNode> cache =
    37           new Hashtable<Integer, DLinkedNode>();
    38   private int size;
    39   private int capacity;
    40   private DLinkedNode head, tail;
    41 
    42   public LRUCache(int capacity) {  // 初始化缓存,构建以伪节点head和tail为开头和结尾的双向链表
    43     this.size = 0;
    44     this.capacity = capacity;
    45     head = new DLinkedNode();
    46     tail = new DLinkedNode();
    47     head.next = tail;
    48     tail.prev = head;
    49   }
    50 
    51   public int get(int key) {
    52     DLinkedNode node = cache.get(key);
    53     if (node == null) return -1;
    54     moveToHead(node);  // 将节点移动到缓存的前面
    55     return node.value;
    56   }
    57 
    58   public void put(int key, int value) {
    59     DLinkedNode node = cache.get(key);
    60     if(node == null) {  // 如果没有的话,添加到里面,注意缓存是否满了
    61       DLinkedNode newNode = new DLinkedNode();
    62       newNode.key = key;
    63       newNode.value = value;
    64       cache.put(key, newNode);
    65       addNode(newNode);
    66       ++size;
    67       if(size > capacity) {
    68         DLinkedNode tail = popTail();
    69         cache.remove(tail.key);
    70         --size;
    71       }
    72     } else {
    73       node.value = value;
    74       moveToHead(node);
    75     }
    76   }
    77 }
  • 相关阅读:
    Swift中的可选链与内存管理(干货系列)
    Swift中的类型转换
    Swift中类与结构的初始化
    Swift3中函数的使用
    Java常用的公共方法
    Eclipse中添加文档注释快捷键
    SVN服务器的搭建(三)
    SVN服务器的搭建(二)
    SVN服务器的搭建(一)
    多线程常见的例子
  • 原文地址:https://www.cnblogs.com/zhang-yi/p/12848979.html
Copyright © 2011-2022 走看看