一、理论
LRU是一种缓存淘汰策略,最近使用的认为是「有用的」,很久没使用过的数据认为是无用的,缓存满时就优先删除它们。
- LRU- Least recently used(最近最少使用页面置换算法、按访问的时序来淘汰)
- LFU- Least frequently used(最近最不常用页面置换算法、按访问频率来淘汰)
LRU缓存算法的核心数据结构:哈希表 + 双向链表
设计的cache需要满足的条件:O(1)查询、O(1)修改、有顺序之分。
哈希表查找快,无序;链表有序,但查找慢。所以结合一下,哈希+链表,借助哈希表赋予链表快速查找的特性。
二、典型例题
☆☆①:设计和实现一个LRU缓存机制(LC146)
方法1:使用LinkedHashMap。属于取巧,面试不大行。。
方法2:HashMap + 手写DoubleList。
方法1:(需要理解LinkedHashMap的源码)
LinkedHashMap的有序可以按两种顺序排列,一种是按照插入的顺序,一种是按照读取的顺序。其内部是靠 建立一个双向链表 来维护这个顺序的。
构造函数:主要是两个构造方法,一个继承HashMap,一个是可选择accessOrder的值(默认false,代表按照插入顺序排序)来确定是按插入顺序还是读取顺序排序。
class LRUCache extends LinkedHashMap<Integer,Integer> { /** * LinkedHashMap的构造函数之一。 * 这里的 accessOrder 默认是为false,如果要按读取顺序排序需要将其设为 true * initialCapacity 代表 map 的 容量,loadFactor 代表加载因子 (默认即可) * public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { * super(initialCapacity, loadFactor); * this.accessOrder = accessOrder; * } */ 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<Integer, Integer> eldest) { return size() > capacity; } }
方法2:HashMap + 手写DoubleList。
参考1、 LRU策略详解和实现
参考2、哈希表 + 双向链表
M. 涉及链表操作细节较多,很具有综合性,以后一定手写完成!!