LFU Cache
2018-11-06 20:06:04
LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。
如何高效的实现一个LFU Cache是一个难点,其实现方式要比LRU要复杂一点,问题的核心就是如果对不同的freq进行计数和维护。这里用到的思路和最大频率栈是类似的,也就是对每个freq都开辟一个Set来进行单独的维护。

为了实现的方便,我们可以在每个freq节点中放入一个LinkedHashSet,这样就可以很方便的进行编码。
public class LFUCache {
    private FreqNode head;
    private FreqNode tail;
    private HashMap<Integer, Integer> key2val;
    private HashMap<Integer, FreqNode> key2node;
    private int capacity;
    public LFUCache(int capacity) {
        this.capacity = capacity;
        this.head = new FreqNode(0);
        this.tail = new FreqNode(Integer.MAX_VALUE);
        this.key2val = new HashMap<>();
        this.key2node = new HashMap<>();
        head.next = tail;
        tail.prev = head;
    }
    public int get(int key) {
        if (capacity == 0) return -1;
        if (key2val.containsKey(key)) {
            int res = key2val.get(key);
            increaseFreq(key);
            return res;
        }
        return -1;
    }
    public void put(int key, int value) {
        if (capacity == 0) return;
        if (key2val.containsKey(key)) {
            key2val.put(key, value);
            increaseFreq(key);
        }
        else {
            maintainSize();
            key2val.put(key, value);
            key2node.put(key, head);
            head.keys.add(key);
            increaseFreq(key);
        }
    }
    private void increaseFreq(int key) {
        FreqNode cur = key2node.get(key);
        FreqNode next = null;
        if (cur.next.freq == cur.freq + 1) {
            next = cur.next;
        }
        else {
            next = new FreqNode(cur.freq + 1);
            next.next = cur.next;
            cur.next.prev = next;
            cur.next = next;
            next.prev = cur;
        }
        next.keys.add(key);
        cur.keys.remove(key);
        key2node.put(key, next);
        if (cur.keys.size() == 0 && cur != head) delete(cur);
    }
    private void maintainSize() {
        if (key2val.size() >= capacity) {
            FreqNode cur = head.next;
            Iterator<Integer> iter = cur.keys.iterator();
            int key = iter.next();
            key2val.remove(key);
            key2node.remove(key);
            cur.keys.remove(key);
            if (cur.keys.size() == 0) delete(cur);
        }
    }
    private void delete(FreqNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
}
class FreqNode {
    public int freq;
    public FreqNode prev ;
    public FreqNode next;
    public LinkedHashSet<Integer> keys;
    public FreqNode(int freq) {
        this.freq = freq;
        prev = null;
        next = null;
        keys = new LinkedHashSet<>();
    }
}
/**
 * Your LFUCache object will be instantiated and called as such:
 * LFUCache obj = new LFUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */
LFU Cache的更多相关文章
- [LeetCode] LFU Cache 最近最不常用页面置换缓存器
		Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ... 
- Leetcode: LFU Cache     &&      Summary of various Sets: HashSet, TreeSet, LinkedHashSet
		Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ... 
- LeetCode LFU Cache
		原题链接在这里:https://leetcode.com/problems/lfu-cache/?tab=Description 题目: Design and implement a data str ... 
- [LeetCode] 460. LFU Cache 最近最不常用页面置换缓存器
		Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the f ... 
- leetcode 146. LRU Cache 、460. LFU Cache
		LRU算法是首先淘汰最长时间未被使用的页面,而LFU是先淘汰一定时间内被访问次数最少的页面,如果存在使用频度相同的多个项目,则移除最近最少使用(Least Recently Used)的项目. LFU ... 
- Leetcode:LRU Cache,LFU Cache
		在Leetcode上遇到了两个有趣的题目,分别是利用LRU和LFU算法实现两个缓存.缓存支持和字典一样的get和put操作,且要求两个操作的时间复杂度均为O(1). 首先说一下如何在O(1)时间复杂度 ... 
- leetcode 460. LFU Cache
		hash:存储的key.value.freq freq:存储的freq.key,也就是说出现1次的所有key在一起,用list连接 class LFUCache { public: LFUCache( ... 
- [LeetCode] LRU Cache 最近最少使用页面置换缓存器
		Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ... 
- 页面置换算法 - FIFO、LFU、LRU
		缓存算法(页面置换算法)-FIFO. LFU. LRU 在前一篇文章中通过leetcode的一道题目了解了LRU算法的具体设计思路,下面继续来探讨一下另外两种常见的Cache算法:FIFO. LFU ... 
随机推荐
- 01: flask基础
			1.1 flask介绍 参考博客: https://www.cnblogs.com/sss4/p/8097653.html 1.django.tornado.flask比较 1. Django:1 ... 
- jtl转化成CSV格式的聚合报告
			1: 从官网下载4.0 的zip 包解压缩,下载地址: https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-4.0.zip ,假 ... 
- python   之   函数的参数
			函数的参数好几种类型:包括位置参数.默认参数.可变参数.关键字参数.命名关键字参数. 廖大神python学习笔记,大神网站:百度搜索“廖雪峰的官网” 1.位置参数:调用函数时根据函数定义的参数位置来传 ... 
- Wxpython零基础制作计算器
			本文关于Wxpython零基础利用python3.6在pycharm下制作计算器,文章末尾有免费源代码供下载 以后同步更新到博客园和这个网站,www.empirefree.top, 这个网站备案号没有 ... 
- Python3 tkinter基础 Listbox height 显示行数的上限
			Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ... 
- Flask学习【第10篇】:自定义Form组件
			wtforms源码流程 实例化流程分析 1 # 源码流程 2 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中: meta类读取到cls._ ... 
- 从Hello World说起(Dart)到“几乎所有东西都是Widget”小部件。
			import 'package:flutter/material.dart'; void main() => runApp(new MyApp()); class MyApp extends S ... 
- jvm:分析工具
			bin/jvisualvm.exe 可查看类实例数 bin/jconsole.exe 监控线程,堆,等 http://blog.csdn.net/yaowj2/article/details/7107 ... 
- [午间休息] - 午间codewars活跃脑袋
			https://www.codewars.com/kata/51f2b4448cadf20ed0000386/javascript 中午是一个易困的时间段.如果其它人不睡觉还好. 这个js题目就是说如 ... 
- ETCD原理
			etcd:从应用场景到实现原理的全方位解读 从etcd的架构开始,深入到源码中解析etcd 1 架构 从etcd的架构图中我们可以看到,etcd主要分为四个部分. HTTP Server: 用于处理用 ... 
