LRU算法(刷题记录)

LFU算法:

LFU(Least Frequently Used)算法每次淘汰使用次数最少的数据。

LFU相当于是把数据按照访问频次进行排序,这个需求恐怕没有那么简单,而且还有一种情况,如果多个数据拥有相同的访问频次,我们就得删除最早插入的那个数据。也就是说LFU算法是淘汰访问频次最低的数据,如果访问频次最低的数据有多条,需要淘汰最久的数据。

LFU算法设计:

1.首先,肯定需要freq到key的映射,用来找到freq最小的key。

2.将freq最小的key删除,那你就得快速得到当前所有key最小的freq是多少。想要时间复杂度O(1)的话,肯定不能遍历一遍去找,那就用一个变量minFreq来记录当前最小的freq

3.可能有多个key拥有相同的freq,所以freq对key是一对多的关系,即一个freq对应一个key的列表

4.希望freq对应的key的列表是存在时序的,便于快速查找并删除最旧的key

5.希望能够快速删除key列表中任何一个key,因为如果频次freq的某个key被访问,那么它的频次就会变成freq+1,就应该从freq对应的key列表中删除,接到freq+1对应的key的列表中。

理解:

主要维护三个表KV(key=>value的映射表)、KF(key=>freq的映射表)、FK(freq=>listhash的映射表)。

listhash是一个哈希链表,自己实现,用于记录某些key使用频次相同时key的时序分布表。

此外,通过minfreq记录所有key值使用的最小频次。

代码:

class Node {
public:
    Node() : key(0), val(0), prev(nullptr), next(nullptr) {};
    Node(int key, int val) : key(key), val(val), prev(nullptr), next(nullptr) {};
    int key, val;
    Node* prev;
    Node* next;
};

class DoubleList {
public:
    DoubleList() {
        head = new Node();
        tail = new Node();
        head->next = tail;
        tail->prev = head;
        sz = 0;
    };

    void addNode(Node* node) {
        node->next = tail;
        node->prev = tail->prev;
        tail->prev->next = node;
        tail->prev = node;
        sz++;
        mp[node->key] = node;
    }

    void seqNode(Node* node) {
        node->next->prev = node->prev;
        node->prev->next = node->next;
        sz--;
        mp.erase(node->key);
    }

    Node* removeNode() {
        if (head->next == tail) {
            return nullptr;
        }
        Node* rm = head->next;
        head->next = rm->next;
        rm->next->prev = head;
        sz--;
        mp.erase(rm->key);
        return rm;
    }

    unordered_map<int, Node*> mp;
private:
    int sz;
    Node* head, * tail;
};

class LFUCache {
public:
    LFUCache(int capacity) {
        cap = capacity;
        minFreq = 0;
    }
    
    int get(int key) {

    }
    
    void put(int key, int value) {
        if (KV.count(key)) {
            KV[key] = value;
            increaseFreq(key);
        } else {
            KV[key] = value;
            cap++;
            
        }
    }

    void increaseFreq(int key) {
        // key对应的freq加一
        int key_freq = KF[key];
        KF[key]++;
        DoubleList* cur = FK[key_freq];
        DoubleList* next;
        if (FK.count(key_freq + 1)) {
            next = FK[key_freq + 1];
        } else {
            next = new DoubleList();
        }
        Node* node = cur->mp[key];
        cur->seqNode(node);
        next->addNode(node);
        FK[key_freq] = next;
    }
private:
    //key->val映射,简称KV表
    unordered_map<int, int> KV;
    //key->freq映射,简称KF表
    unordered_map<int, int> KF;
    //freq->keys映射,简称FK表
    unordered_map<int, DoubleList*> FK;
    //记录最小的频次
    int minFreq;
    //记录LFU缓存的最大容量
    int cap;
};

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

学习参考:labuladong 的知识店铺

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值