NC设计LFU缓存结构

系列文章目录



前言

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。
在这里插入图片描述


描述
一个缓存结构需要实现如下功能。
set(key, value):将记录(key, value)插入该结构
get(key):返回key对应的value值
但是缓存结构中最多放K条记录,如果新的第K+1条记录要加入,就需要根据策略删掉一条记录,然后才能把新记录加入。这个策略为:在缓存结构的K条记录中,哪一个key从进入缓存结构的时刻开始,被调用set或者get的次数最少,就删掉这个key的记录;
如果调用次数最少的key有多个,上次调用发生最早的key被删除
这就是LFU缓存替换算法。实现这个结构,K作为参数给出

若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1

对于每个操作2,返回一个答案
在这里插入图片描述

import java.util.*;
public class Solution {
    //设置节点结构
    static class Node{ 
        int freq;
        int key;
        int val;
        //初始化
        public Node(int freq, int key, int val) {
            this.freq = freq;
            this.key = key;
            this.val = val;
        }
    }
    //频率到双向链表的哈希表
    private Map<Integer, LinkedList<Node> > freq_mp = new HashMap<>();
    //key到节点的哈希表
    private Map<Integer, Node> mp = new HashMap<>();
    //记录缓存剩余容量
    private int size = 0; 
    //记录当前最小频次
    private int min_freq = 0;
    
    public int[] LFU (int[][] operators, int k) {
        //构建初始化连接
        //链表剩余大小
        this.size = k;
        //获取操作数
        int len = (int)Arrays.stream(operators).filter(x -> x[0] == 2).count();
        int[] res = new int[len];
        //遍历所有操作
        for(int i = 0, j = 0; i < operators.length; i++){
            if(operators[i][0] == 1)
                //set操作
                set(operators[i][1], operators[i][2]);
            else
                //get操作
                res[j++] = get(operators[i][1]);
        }
        return res;
    }
    
    //调用函数时更新频率或者val值
    private void update(Node node, int key, int value) { 
        //找到频率
        int freq = node.freq;
        //原频率中删除该节点
        freq_mp.get(freq).remove(node); 
        //哈希表中该频率已无节点,直接删除
        if(freq_mp.get(freq).isEmpty()){ 
            freq_mp.remove(freq);
            //若当前频率为最小,最小频率加1
            if(min_freq == freq) 
                min_freq++;
        }
        if(!freq_mp.containsKey(freq + 1))
            freq_mp.put(freq + 1, new LinkedList<Node>());
        //插入频率加一的双向链表表头,链表中对应:freq key value
        freq_mp.get(freq + 1).addFirst(new Node(freq + 1, key, value)); 
        mp.put(key, freq_mp.get(freq + 1).getFirst());
    }
    
    //set操作函数
    private void set(int key, int value) {
        //在哈希表中找到key值
        if(mp.containsKey(key)) 
            //若是哈希表中有,则更新值与频率
            update(mp.get(key), key, value);
        else{ 
            //哈希表中没有,即链表中没有
            if(size == 0){
                //满容量取频率最低且最早的删掉
                int oldkey = freq_mp.get(min_freq).getLast().key; 
                //频率哈希表的链表中删除
                freq_mp.get(min_freq).removeLast(); 
                if(freq_mp.get(min_freq).isEmpty()) 
                    freq_mp.remove(min_freq); 
                //链表哈希表中删除
                mp.remove(oldkey); 
            }
            //若有空闲则直接加入,容量减1
            else 
                size--; 
            //最小频率置为1
            min_freq = 1; 
            //在频率为1的双向链表表头插入该键
            if(!freq_mp.containsKey(1))
                freq_mp.put(1, new LinkedList<Node>());
            freq_mp.get(1).addFirst(new Node(1, key, value)); 
            //哈希表key值指向链表中该位置
            mp.put(key, freq_mp.get(1).getFirst()); 
        }
    }
    
    //get操作函数
    private int get(int key) {
        int res = -1;
        //查找哈希表
        if(mp.containsKey(key)){ 
            Node node = mp.get(key);
            //根据哈希表直接获取值
            res = node.val;
            //更新频率 
            update(node, key, res); 
        }
        return res;
    }
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这是一个 Python 实现的 LFU 缓存: ```python from collections import defaultdict class LFUCache: def __init__(self, capacity): self.capacity = capacity self.cache = {} self.freq = defaultdict(OrderedDict) self.min_freq = 0 def get(self, key): if key not in self.cache: return -1 value, freq = self.cache[key] self.freq[freq].pop(key) if len(self.freq[freq]) == 0: self.freq.pop(freq) if self.min_freq == freq: self.min_freq += 1 self.freq[freq+1][key] = value self.cache[key] = (value, freq+1) return value def put(self, key, value): if self.capacity == 0: return if key in self.cache: self.cache[key] = (value, self.cache[key][1]) self.get(key) return if len(self.cache) == self.capacity: k, v = self.freq[self.min_freq].popitem(last=False) self.cache.pop(k) self.cache[key] = (value, 1) self.freq[1][key] = value self.min_freq = 1 ``` 该实现中,LFU 缓存使用了一个字典 `cache` 来存储 key-value 对,使用一个字典 `freq` 来记录每个频次对应的 key-value 对,使用变量 `min_freq` 来记录当前最小的频次。 在 `get` 方法中,如果 key 不存在于 `cache` 中,则返回 -1。否则,将 key 对应的 value 和频次从 `freq` 中删除,如果该频次对应的 key-value 对已经为空,则将该频次从 `freq` 中删除,并更新 `min_freq`。然后,将 key 对应的 value 和频次加一后添加到 `freq` 中,并更新 `cache` 中的 key-value 对。 在 `put` 方法中,如果 `capacity` 为 0,则直接返回。如果 key 已存在于 `cache` 中,则将 `cache` 中的 key-value 对更新,并调用 `get` 方法以更新 `freq` 和 `min_freq`。如果 `cache` 已经满了,则从 `freq` 中删除当前最小频次的 key-value 对,并从 `cache` 中删除对应的 key-value 对。然后,将新的 key-value 对添加到 `cache` 和 `freq` 中,并将 `min_freq` 设置为 1。 使用示例: ```python cache = LFUCache(2) cache.put(1, 1) cache.put(2, 2) assert cache.get(1) == 1 cache.put(3, 3) assert cache.get(2) == -1 assert cache.get(3) == 3 cache.put(4, 4) assert cache.get(1) == -1 assert cache.get(3) == 3 assert cache.get(4) == 4 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java毕设王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值