public class LFUCache<K, V> { private final int capacity; private Map<K, V> cache; private Map<K, Integer> freqMap; private Map<Integer, LinkedHashSet<K>> freqKeysMap; private int minFreq;
public LFUCache(int capacity) { this.capacity = capacity; cache = new HashMap<>(); freqMap = new HashMap<>(); freqKeysMap = new HashMap<>(); minFreq = 0; }
public V get(K key) { if (!cache.containsKey(key)) { return null; } int freq = freqMap.get(key); freqMap.put(key, freq + 1); freqKeysMap.get(freq).remove(key); if (freq == minFreq && freqKeysMap.get(freq).size() == 0) { minFreq++; } if (!freqKeysMap.containsKey(freq + 1)) { freqKeysMap.put(freq + 1, new LinkedHashSet<>()); } freqKeysMap.get(freq + 1).add(key); return cache.get(key); }
public void put(K key, V value) { if (capacity <= 0) { return; } if (cache.containsKey(key)) { cache.put(key, value); get(key); return; } if (cache.size() >= capacity) { K evictKey = freqKeysMap.get(minFreq).iterator().next(); freqKeysMap.get(minFreq).remove(evictKey); cache.remove(evictKey); freqMap.remove(evictKey); } cache.put(key, value); freqMap.put(key, 1); minFreq = 1; if (!freqKeysMap.containsKey(1)) { freqKeysMap.put(1, new LinkedHashSet<>()); } freqKeysMap.get(1).add(key); } }
LFU 缓存在处理缓存置换的时候会考虑到访问频率的因素。如果缓存空间已满,那么就要淘汰掉一些数据,以腾出空间存放新的数据。常见的淘汰算法有:先进先出(First In First Out,FIFO)、最近最少使用(Least Recently Used,LRU)和最不经常使用(Least Frequently Used,LFU)等。