LeetCode460 LFU缓存

struct Node {      //双向链表的节点
    int key;  //键
    int val;  //值
    int freq;  //频率
    Node* prev;  //前一个节点
    Node* next;  //后一个节点
    //无参构造函数
    Node () : key(-1), val(-1), freq(0), prev(nullptr), next(nullptr) {}
    //带参构造函数
    Node (int _k, int _v) : key(_k), val(_v), freq(1), prev(nullptr), next(nullptr) {}
};

struct FreqList {   //双向链表
    int freq;  //频率
    Node* vhead; //链表头
    Node* vtail; //链表尾
    //构造函数
    FreqList (int _f) : freq(_f), vhead(new Node()), vtail(new Node()) {
        vhead->next = vtail;
        vtail->prev = vhead;
    }
};




class LFUCache {
private:
    unordered_map<int, Node*> occ;   //键 和 键值对 对应 
    unordered_map<int, FreqList*> freq_map;  //频率 和 双向链表对应
    int sz; //大小
    int min_freq;  //最小的频率
public:

    //构造函数
    LFUCache (int capacity) : sz(capacity) {}

    //判断双向链表是否为空
    bool empty(FreqList* l) {
        return l->vhead->next == l->vtail ? true : false;
    }

    //删除双向链表中的节点
    void deleteNode (Node* t) {
        t->prev->next = t->next;
        t->next->prev = t->prev;
    }
    //将节点添加到头部
    void addHead (Node* t) {
        int freq = t->freq;  //获得节点的频率
        if (freq_map.find(freq) == freq_map.end()) {  //在频率哈希表中找不到该频率
            freq_map[freq] = new FreqList(freq);   //新建一个双向链表
        }
        FreqList* l = freq_map[freq];  //获得该双向链表
        t->next = l->vhead->next;      //将节点添加到链表头
        l->vhead->next->prev = t;
        t->prev = l->vhead;
        l->vhead->next = t;
    }
    //删除双向链表的尾部
    void popTail () {
        Node* t = freq_map[min_freq]->vtail->prev;  //获得最后一个节点
        deleteNode(t);  //删除该节点
        occ.erase(t->key);  //删除occ中的映射
    }
    
    int get (int key) {
        int res = -1;
        if (occ.find(key) != occ.end()) {   //找到了key
            Node* t = occ[key];  //获得该key对应的节点
            res = t->val;  //保存结果
            deleteNode(t); //删除这个节点
            t->freq++;  //更新访问频率
            if (empty(freq_map[min_freq])) min_freq++;  //如果最小频率对应的链表为空,将最小频率加1
            addHead(t);   //将t添加到对应频率的双向链表的最前面
        }
        return res;  //返回结果
    }
    
    void put (int key, int value) {
        if (sz == 0) return;   //如果缓存的大小为0,返回
        if (get(key) != -1) {   //如果找的到
            occ[key]->val = value;  //更新值
        }
        else {
            if (occ.size() == sz) {  //如果已经满了
                popTail();   //删除最后一个节点
            }
            Node* t = new Node(key, value);  //生成一个新的节点
            occ[key] = t;  //添加到映射表occ中
            min_freq = 1;//新插入的 频率一定最少, 为1   //设置最小的频率为1
            addHead(t);  //添加到对应频率的最前面
        }
    }
};

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

猜你喜欢

转载自blog.csdn.net/m0_38062470/article/details/114452149