标签:amp 第一个 cache 一个 日常 严格 als hashset array
leetcode题目-16.25.LRU缓存
设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。 它应该支持以下操作: 获取数据 get 和 写入数据 put 。 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/lru-cache-lcci 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
即如果一组数字,最近使用的放在最左边,最近不用的放在最右边。因此如果新写入一个数字,如果内存满了,就把最右边的数字替换掉,新来的数字放在最左边。如果新获取一个数据,那么这个数据就是最新使用的了,就更新它的位置。
因此这组数据需要频繁地换位置,肯定是要使用链表的。
//LinkedHashMap实现
class LRUCache { int capacity; Map<Integer, Integer> map; public LRUCache(int capacity) { this.capacity = capacity; map = new LinkedHashMap<>(); } public int get(int key) { //若密钥不存在缓存中,则返回-1 if(!map.containsKey(key)){ return -1; } //如果密钥存在缓存中,则获取密钥的值 Integer value = map.remove(key); map.put(key, value); return value; } public void put(int key, int value) { //如果密钥存在,删出原数值.即更新该数值的位置 if(map.containsKey(key)){ map.remove(key); map.put(key, value); return; } //如果密钥不存在,写入其数据值 map.put(key, value); //如果缓存容量达到上限,那么删出最近最少使用的数据 //利用迭代器,删出第一个 if(map.size()>capacity){
//map.entrySet():把HashMap类型的数据转换为集合类型,获取键值对的集合
//iterator():获取这个集合的迭代器 map.remove(map.entrySet().iterator().next().getKey()); } } }
//双向链表+HashMap
public class LRUCache{ //定义双向链表节点 private class ListNode{ int key; int value; ListNode pre; ListNode next; public ListNode(int key, int value){ this.key = key; this.value = value; pre = null; next = null; } } private int capacity; private Map<Integer, ListNode> map; //虚拟头节点 private ListNode head; //虚拟尾节点 private ListNode tail; //初始化 public LRUCache(int capacity){ this.capacity = capacity; map = new HashMap<>(); head = new ListNode(-1, -1); tail = new ListNode(-1, -1); //建立虚拟头节点和尾节点的关系 head.next = tail; tail.pre = head; } public int get(int key){ //若密钥不存在缓存中,则返回-1 if(!map.containsKey(key)){ return -1; } //如果密钥存在缓存中,则获取密钥的值 ListNode node = map.get(key); //更新密钥对应值的位置到尾部.即删出当前节点 node.pre.next = node.next; node.next.pre = node.pre; moveToTail(node); return node.value; } public void put(int key, int value){ //如果密钥存在,删出原数值.即更新该数值的位置 if(get(key) != -1){ map.get(key).value = value; return; } //如果密钥不存在,写入其数据值 ListNode node = new ListNode(key, value); map.put(key, node); moveToTail(node); //如果缓存容量达到上限,那么删出最近最少使用的数据。删除头(虚拟头节点后面的节点) if(map.size() > capacity){ map.remove(head.next.key); head.next = head.next.next; head.next.pre = head; } } //将节点移动到链表的末尾,虚拟尾节点的前面 private void moveToTail(ListNode node){ node.pre = tail.pre; tail.pre = node; node.pre.next = node; node.next = tail; } }
LRU应用场景:
日常开发中,UI界面加载图片不可能每次都从网络上下载然后显示,因此Android提供了LruCache类,用于图片的内存缓存。
A cache that holds strong references to a limited number of values. Each time a value is accessed, it is moved to the head of a queue. When a value is added to a full cache, the value at the end of that queue is evicted and may become eligible for garbage collection. 一个包含有限数量强引用(平常使用的对象引用方式)的缓存,每次访问一个值,它都会被移动到队列的头部,将一个新的值添加到已经满了的缓存队列时,该队列末尾的值将会被逐出,并且可能会被垃圾回收机制进行回收。
内部实现是通过LinkedHashMap维护一个缓存对象列表。参数分别为初始容量、加载因子、访问顺序(为true即集合的元素顺序是访问顺序,访问后会将该元素放到集合的最后面;为false即按照插入顺序)。
初始容量的设置:如初始大小小于1,那么map大小默认为1;否则不断*2直到大于设置的初始容量。
总缓存大小一般为可用内存的1/8
另一种采用LRU算法的缓存为DisLruCahce,用于实现硬盘缓存。
Java的集合:
迭代器iterator
Java采用迭代器为各种容器提供公共的操作接口,使得对容器的遍历操作与具体的底层实现相隔离。
“Collection集合元素的通用获取方式:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。”
因此迭代器要实现两个方法:
hasNext():仍有元素可迭代,返回true;
next():返回迭代的下一个元素。
标签:amp 第一个 cache 一个 日常 严格 als hashset array
原文地址:https://www.cnblogs.com/lyeeer/p/13382153.html