JAVA实现的LFU算法

使用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
}
相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
小羊没烦恼!2 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
俊昭喜喜里2 天前
java中的继承和多态的区别
java
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
譕痕2 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码2 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖2 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时2 天前
01-06-A-JVM排查实战详解
java·jvm