资讯专栏INFORMATION COLUMN

LFU

whidy / 1229人阅读

摘要:如果每一个频率放在一个里面,每个也有头尾两个指针,指向相邻的。实际上相邻的可以由的第一可以由的最后一个唯一确认。也就是说,在的设计基础上。也就是说频率为的点,指向的下一个是频率为的点移除和一样。里存在的点,加到尾部的后一个。

只个代码由LRU改进得到。
如果每一个频率放在一个LRU里面,每个LRU也有头尾两个指针,指向相邻的LRU。
实际上相邻的LRU可以由frequency = t+1的第一node,可以由frequency = t的最后一个唯一确认。
也就是说,在LRU的设计基础上。我们再多记录一个finalNodes,记录每种频率的尾部就好了。

代码因为情况较多,所以要分析好了,才能归并。

频率可以不连续,最小频率也不一定为1. 我们put(1,1), get(1) LFU里现在只有这个点,频率为2,最小频率不是1.
我们在put(2,2), get(2),get(2), get(2). 2出现了4次。 也就是说频率为2的点1, 指向的下一个是频率为4的点2.

移除node和LRU一样。

添加node,

map里不存在的要加到头部。
2.1 map里存在的点,加到freq + 1尾部的后一个。

2.2 如果刚好freq+1这个频率不存在(也就是freq+1在finalNodes里没有,我们就不需要移动。)

public class LFUCache {
    private int capacity;
    private int count;
    private HashMap map1; // whether appeared
    private HashMap finalNodes; // value : the final node of key times
    private Tuple dummyHead;
    private Tuple dummyEnd;
    
    public LFUCache(int capacity) {
        this.capacity = capacity;
        count = 0;
        map1 = new HashMap();
        finalNodes = new HashMap<>();
        dummyHead = new Tuple(0, 0, 0);
        dummyEnd = new Tuple(0, 0, 0);
        dummyHead.next = dummyEnd;
        dummyEnd.prev = dummyHead;
    }
    
    public int get(int key) {
        if (capacity == 0 || !map1.containsKey(key)) {
            return -1;
        }
        Tuple old = map1.get(key);
        put(key, old.value);
        return old.value;
    }
    
    public void put(int key, int value) {
        if (capacity == 0) {
            return;
        }
        if (map1.containsKey(key)) { // this key has appeared
            Tuple cur = map1.get(key);
            if (finalNodes.get(cur.times) == cur && finalNodes.get(cur.times + 1) == null) { // the position should not change
                finalNodes.put(cur.times, cur.prev.times == cur.times ? cur.prev : null);
                cur.times++;
                cur.value = value;
                finalNodes.put(cur.times, cur);
                return;
            }
            removeNode(cur); // remove node cur
            if (finalNodes.get(cur.times) == cur) {
                finalNodes.put(cur.times, cur.prev.times == cur.times ? cur.prev : null);
            }
            cur.times++;
            cur.value = value;
            Tuple finalNode = finalNodes.get(cur.times) == null ? finalNodes.get(cur.times - 1) : finalNodes.get(cur.times);
            insertNode(finalNode, cur); 
            finalNodes.put(cur.times, cur); 
        } else {
            if (count == capacity) { // reach limt of the cache
                Tuple head = dummyHead.next;
                removeNode(head); //remove the first which appeared least times and is the least Used
                map1.remove(head.key);
                if (finalNodes.get(head.times) == head) {
                    finalNodes.remove(head.times);
                }
            } else {
                count++;
            } 
            insertHead(key, value);
        } 
    }
    
    public void insertHead(int key, int value) {
        Tuple cur = new Tuple(key, value, 1);
            if (finalNodes.get(1) == null) {
                insertNode(dummyHead, cur);
            } else {
                Tuple finalNode = finalNodes.get(1);
                insertNode(finalNode, cur);
            }
            finalNodes.put(1, cur);
            map1.put(key, cur);
    }
    
    public void insertNode(Tuple t1, Tuple t2) {
        t2.next = t1.next;
        t1.next.prev = t2;
        t1.next = t2;
        t2.prev = t1;
    }
    
    public void removeNode(Tuple node) {
        node.next.prev = node.prev;
        node.prev.next = node.next;
    }
    
    class Tuple {
        int key;
        int value;
        int times;
        Tuple prev;
        Tuple next;
        public Tuple(int key, int value, int times) {
            this.key = key;
            this.value = value;
            this.times = times;
        }
    }
}

/**
 * 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);
 */

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/66584.html

相关文章

  • 论文《TinyLFU: A Highly Ecient Cache Admission Polic

    摘要:在静态的频率分布下,性能也落后于因为其不再为不在缓存中的数据维护任何频率数据。可以详见的准入淘汰策略是新增一个新的元素时,判断使用该元素替换一个旧元素,是否可以提升缓存命中率。 1. Introduction LFU的局限: LFU实现需要维护大而复杂的元数据(频次统计数据等) 大多数实际工作负载中,访问频率随着时间的推移而发生根本变化(这是外卖业务不适合朴素LFU的根本原因) 针...

    高璐 评论0 收藏0
  • 论文《TinyLFU: A Highly Ecient Cache Admission Polic

    摘要:在静态的频率分布下,性能也落后于因为其不再为不在缓存中的数据维护任何频率数据。可以详见的准入淘汰策略是新增一个新的元素时,判断使用该元素替换一个旧元素,是否可以提升缓存命中率。 1. Introduction LFU的局限: LFU实现需要维护大而复杂的元数据(频次统计数据等) 大多数实际工作负载中,访问频率随着时间的推移而发生根本变化(这是外卖业务不适合朴素LFU的根本原因) 针...

    RobinQu 评论0 收藏0
  • Redis 缓存淘汰策略

    摘要:但是内存空间毕竟有限,随着我们存储数据的不断增长,要缓存的数据量越来越大,当超过了我们的内存大小时,该怎么办呢解决方法有两种增加物理内存搭建集群和缓存数据的淘汰机制。增加物理内存简单粗暴,价格十分昂贵,内存的价格大约是万元左右。redis 使用的时内存空间来存储数据的,避免业务应用从后端数据库中读取数据,可以提升应用的响应速度。但是内存空间毕竟有限,随着我们存储数据的不断增长,要缓存的数据量...

    Tecode 评论0 收藏0
  • 你与解决“缓存污染”只差这篇文章的距离

    摘要:如果处理不得当,就会造成缓存污染问题。解决缓存污染的算法算法,英文名,字面意思就是最不经常使用的淘汰掉算法,是通过数据被访问的频率来判断一个数据的热点情况。分析降低了缓存污染带来的问题,命中率比要高。 微信公众号:IT一刻钟大型现实非严肃主义现场一刻钟与你分享优质技术架构与见闻,做一个有剧情的程序员关注可第一时间了解更多精彩内容,定期有福利相送哟。 showImg(https://s...

    shadowbook 评论0 收藏0

发表评论

0条评论

whidy

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<