使用JAVA语言实现常用的LFU(Least Frequently Used)算法
定义一个LFUNode类来表示LFU缓存中的节点
java
private static class LFUNode<K, V> {
K key;
V value;
int frequency;
public LFUNode(K k, V v) {
key = k;
value = v;
frequency = 1;
}
}
接下来,我们创建一个LFUCache类来实现LFU缓存。在初始化函数中,我们需要指定缓存的最大容量。
java
public class LFUCache1<K, V> {
private int capacity;
private Map<K, LFUNode<K, V>> cacheMap;
private Map<Integer, LinkedHashSet<LFUNode<K, V>>> frequencyMap;
private int minFrequency;
public void init(int size) {
this.capacity = size;
cacheMap = new HashMap<>();
frequencyMap = new HashMap<>();
minFrequency = 0;
}
...
接下来,我们实现两个辅助方法:
addToFrequencyMap
:将节点添加到对应频率的链表中。removeFromFrequencyMap
:从对应频率的链表中移除节点。
java
private void addToFrequencyMap(LFUNode<K, V> node) {
int frequency = node.frequency;
frequencyMap.putIfAbsent(frequency, new LinkedHashSet<>());
frequencyMap.get(frequency).add(node);
if (frequency == 1) {
minFrequency = 1;
}
}
java
private void removeFromFrequencyMap(LFUNode<K, V> node) {
int frequency = node.frequency;
frequencyMap.get(frequency).remove(node);
if (frequency == minFrequency && frequencyMap.get(frequency).size() == 0) {
minFrequency++;
}
}
最后实现核心方法:get
和put
java
public V get(K key) {
if (cacheMap.containsKey(key)) {
LFUNode<K, V> node = cacheMap.get(key);
removeFromFrequencyMap(node);
node.frequency++;
addToFrequencyMap(node);
return node.value;
}
return null;
}
java
public void put(K key, V value) {
if (capacity <= 0) {
return;
}
if (cacheMap.containsKey(key)) {
LFUNode<K, V> node = cacheMap.get(key);
removeFromFrequencyMap(node);
node.value = value;
node.frequency++;
addToFrequencyMap(node);
} else {
if (cacheMap.size() >= capacity) {
LinkedHashSet<LFUNode<K, V>> minFrequencySet = frequencyMap.get(minFrequency);
LFUNode<K, V> evictNode = minFrequencySet.iterator().next();
minFrequencySet.remove(evictNode);
cacheMap.remove(evictNode.key);
}
LFUNode<K, V> newNode = new LFUNode<>(key, value);
cacheMap.put(key, newNode);
addToFrequencyMap(newNode);
minFrequency = 1;
}
}
最终验证结果如下:
java
@Test
public void testCase() {
LFUCache1<Integer, String> cache = new LFUCache1<>();
cache.init(2);
cache.put(1, "Hello");
cache.put(2, "World");
System.out.println(cache.get(1)); // Output: Hello
cache.put(3, "Foo");
System.out.println(cache.get(2)); // Output: null (evicted)
System.out.println(cache.get(3)); // Output: Foo
}