LFU缓存

https://leetcode-cn.com/problems/lfu-cache/description/

缓存的实现可以采取多种策略,不同策略优点的评估就是“命中率”。好的策略可以实现较高的命中率。常用的策略如:LRU(最近最少使用)、LFU(最不频繁使用)。这两种策略都可以在O(1)时间内实现get和put。本文主要讲讲LFU的实现。

import java.util.HashMap;
import java.util.LinkedHashSet;

class LFUCache {

    public int capacity;//容量大小
    public HashMap<Integer, Integer> map = new HashMap<>();//存储put进去的key和value
    public HashMap<Integer, Integer> frequent = new HashMap<>();//存储每个key的频率值
    //存储每个频率的相应的key的值的集合,这里用HashSet是因为其是由HashMap底层实现的,可以O(1)时间复杂度查找元素
    //而且linked是有序的,同一频率值越往后越最近访问
    public HashMap<Integer, LinkedHashSet<Integer>> list = new HashMap<>();
    int min = -1;//标记当前频率中的最小值

    public LFUCache(int capacity) {
        this.capacity = capacity;
    }

    public int get(int key) {
        if(!map.containsKey(key)){
            return -1;
        }else{
            int value = map.get(key);//获取元素的value值
            int count = frequent.get(key);
            frequent.put(key, count + 1);

            list.get(count).remove(key);//先移除当前key

            //更改min的值
            if(count == min && list.get(count).size() == 0)
                min++;

            LinkedHashSet<Integer> set = list.containsKey(count + 1) ? list.get(count + 1) : new LinkedHashSet<Integer>();
            set.add(key);
            list.put(count + 1, set);

            return value;
        }

    }

    public void put(int key, int value) {
        if(capacity <= 0){
            return;
        }
        //这一块跟get的逻辑一样
        if(map.containsKey(key)){
            map.put(key, value);
            int count = frequent.get(key);
            frequent.put(key, count + 1);

            list.get(count).remove(key);//先移除当前key

            //更改min的值
            if (count == min && list.get(count).size() == 0)
                min++;

            LinkedHashSet<Integer> set = list.containsKey(count + 1) ? list.get(count + 1) : new LinkedHashSet<Integer>();
            set.add(key);
            list.put(count + 1, set);
        }else{
            if(map.size() >= capacity){
                Integer removeKey = list.get(min).iterator().next();
                list.get(min).remove(removeKey);
                map.remove(removeKey);
                frequent.remove(removeKey);
            }
            map.put(key, value);
            frequent.put(key, 1);
            LinkedHashSet<Integer> set = list.containsKey(1) ? list.get(1) : new LinkedHashSet<Integer>();
            set.add(key);
            list.put(1, set);

            min = 1;
        }

    }

    public static void main(String[] args) {
        LFUCache lfuCache = new LFUCache(2);
        lfuCache.put(2, 1);
        lfuCache.put(3, 2);
        System.out.println(lfuCache.get(3));
        System.out.println(lfuCache.get(2));
        lfuCache.put(4, 3);
        System.out.println(lfuCache.get(2));
        System.out.println(lfuCache.get(3));
        System.out.println(lfuCache.get(4));
    }
}

参考资料

http://www.cnblogs.com/DarrenChan/p/8819996.html

原文地址:https://www.cnblogs.com/weiyinfu/p/8822876.html

时间: 2024-10-15 01:35:55

LFU缓存的相关文章

-实现 LFU 缓存算法

-实现 LFU 缓存算法, 设计一个类 LFUCache,实现下面三个函数 + 构造函数: 传入 Cache 内最多能存储的 key 的数量 + get(key):如果 Cache 中存在该 key,则返回对应的 value 值,否则,返回-1. + set(key,value):如果 Cache 中存在该 key,则重置 value 值:如果不存在该 key,则将该 key 插入到到 Cache 中,若插入后会导致 Cache 中存储的 key 个数超过最大容量,则在插入前淘汰访问次数最少的数

【Leetcode刷题】LFU缓存

题目:https://leetcode-cn.com/problems/lfu-cache/ 思路: O(1)的数据结构:hashmap 维持最近使用:OrderdDict(详见LRU缓存问题) 使用一个hashmap维系key到出现频率的映射关系 另一个hashmap维系频率到数据(key-value键值对)的关系 由于 当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近 最少使用的键.因此key-value键值对应该用OrderdDict存储 import collection

460. LFU缓存

题目地址:https://leetcode-cn.com/problems/lfu-cache/submissions/ 代码地址:https://github.com/javartisan/edx-ds/blob/master/src/main/java/com/javartisan/leetcode/LFUCache460.java class LFUCache { private static class Node{ public int key=-1; public int value=

leetcode 460 LFU缓存

原题点这里 class Node implements Comparable<Node>{ public int key; public int value; public int lastTime; public int fre; public Node(int key,int value,int lastTime){ this.key=key; this.value=value; this.lastTime = lastTime; this.fre=1; } @Override publi

详解三种缓存过期策略LFU,FIFO,LRU(附带实现代码)

在学操作系统的时候,就会接触到缓存调度算法,缓存页面调度算法:先分配一定的页面空间,使用页面的时候首先去查询空间是否有该页面的缓存,如果有的话直接拿出来,如果没有的话先查询,如果页面空间没有满的时候,使用新页面的时候,就释放旧的页面空间,把新页面缓存起来,以便下次使用同样的页面的时候方便调用. 缓存调度流程图 缓存机制就是上面所说的那样,但是实现的过程以及淘汰旧页面的机制不同,所以会有不同缓存调度方法,就常见的就是FIFO,LRU,LFU缓存过期策略. 1.FIFO(First In First

【转】缓存淘汰算法系列之2——LFU类

原文地址 :http://www.360doc.com/content/13/0805/16/13247663_304916783.shtml 1. LFU类 1.1. LFU 1.1.1. 原理 LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”. 1.1.2. 实现 LFU的每个数据块都有一个引用计数,所有数据块按照引用计数排序,具有相同引用计数的数据块则按照时间排序. 具体实现如下:

[转]缓存、缓存算法和缓存框架简介

以下内容转自:http://www.leexiang.com/cache-algorithm (转载请注明出处)-----------------------------------分割线---------------------------------------------- 引言 我们都听过 cache,当你问他们是什么是缓存的时候,他们会给你一个完美的答案,可是他们不知道缓存是怎么构建的,或者没有告诉你应该采用什么标准去选择缓存框架.在这边文章,我们会去讨论缓存,缓存算法,缓存框架以及哪

缓存、缓存算法和缓存框架

译者:lixiang 译文:http://www.zavakid.com/25 原文:http://www.jtraining.com/component/content/article/35-jtraining-blog/98.html 引言 我们都听过 cache,当你问他们是什么是缓存的时候,他们会给你一个完美的答案,可是他们不知道缓存是怎么构建的,或者没有告诉你应该采用什么标准去选择缓存框架.在这边文章,我们会去讨论缓存,缓存算法,缓存框架以及哪个缓存框架会更好. 面试 “缓存就是存贮数

缓存、缓存算法和缓存框架简介

文章转载于:http://blog.jobbole.com/30940/ 引言 我们都听过 cache,当你问他们是什么是缓存的时候,他们会给你一个完美的答案,可是他们不知道缓存是怎么构建的,或者没有告诉你应该采用什么标准去选择缓存框架.在这边文章,我们会去讨论缓存,缓存算法,缓存框架以及哪个缓存框架会更好. 面试 “缓存就是存贮数据(使用频繁的数据)的临时地方,因为取原始数据的代价太大了,所以我可以取得快一些.” 这就是 programmer one (programmer one 是一个面试