最近阿里巴巴电话面试被问到了如何使用固定容量的HashMap,实现LRU算法。当时一脸懵逼,平时用HashMap也就用来快速存取数据而已,容量都是不限的。
想了半天,想到对node节点进行扩展,加入引用计数,然后到达指定容量后,删除引用计数最少的。
面试官质疑这样效率太低了,能不能优化下。
想到删除时,需要遍历所有元素,代价为O(n),太大了。想到可以用最小堆来进行筛选。被问到建堆的节点值是什么,这块没想好,卡壳了。
面试完之后,网上搜了下,才发现Java官方已经替我们预留了LRU算法的框架,在LinkedHashMap里。我们只需要扩展下即可,代码示例如下:
/**
* Constructs an empty <tt>LinkedHashMap</tt> instance with the
* specified initial capacity, load factor and ordering mode.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @param accessOrder the ordering mode - <tt>true</tt> for
* access-order, <tt>false</tt> for insertion-order
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
//方法为protected ,摆明了是想被继承、重写
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
使用accessOrder来标识是使用访问顺序,还是插入顺序。默认为插入顺序。当accessOrder为访问顺序、容量固定时,即为LRU
举例如下:
class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V> {
/**
*
*/
private static final long serialVersionUID = 1882839504956564761L;
private int capacity;
public LRULinkedHashMap(int capacity) {
super</