[LeetCode] LRU和LFU详解之二

在上一篇文章中,我们介绍LRU和LFU的概念、共同点及其主要差别,并且详细介绍了LRU的C++实现。本文将继续对LFU进行分析与详解,并给出C++实现代码。

与LRU纯粹比较数据使用时间与当前时间的远近不同,LFU的核心思想如果数据在最近一段时间内访问次数越少,那么将来被访问的几率也越低。因此在设计LFU时,我们需要引进变量:频率frequency,并且需要根据频率值来决定节点的删除操作。这里需要注意的是:当几个节点的频率都相同时,采用LRU的思想,优先删除的是最近最少使用的节点。

根据以上的分析,首先我们需要在节点上增加一个变量freq记录节点的频率。其次,除了LRU中key与Node的map之外,对于每一个频率值,我们还需要一个list 来记录在这一频率值下的节点。因此我们增加一个频率与list的map:freqMap。另外,为了迅速找到并删除节点,我们在Node结构中增加iterator,记录frequency list的头部。

节点的定义和LFU的结构如下:

struct Node{
        int val;
        int freq;
        list::iterator it;
        Node():freq(1){}
        Node(int value):val(value),freq(1){}
    };
class LFUCache {
public:
    LFUCache(int capacity) {
        this->capacity = capacity;
    }

private:
    int capacity;
    int minFreq;
    unordered_map cacheMap;
    unordered_map> freqMap;
};

get(int key)函数的设计与LRU中get函数类似。需要注意的是这里更新节点不再是将节点移到到链表尾部,而是更新节点的freq,将原节点从以前的freq list中移除,添加到新的freq list前端,最后更新节点的iterator。


    int get(int key) {
        //if not exist
        if(cacheMap.find(key) == cacheMap.end()) return -1;
        
        Node* node = cacheMap[key];
        //update freq
        freqMap[node->freq].erase(node->it);
        node->freq += 1;
        freqMap[node->freq].push_front(key);
        node->it = freqMap[node->freq].begin();
        if(freqMap[minFreq].size()==0)
            minFreq = node->freq;
        
        return node->val;
    }

put(int key, int value)的设计同样需要注意对freq list的处理。


    void put(int key, int value) {
        if(capacity <= 0) return;
        
        if(get(key) == -1)
        {
            if(cacheMap.size()==capacity)
            {
                //remove
                int popkey = freqMap[minFreq].back();
                cacheMap.erase(popkey);
                freqMap[minFreq].pop_back();
            }
            
            //insert new node
            Node*  node = new Node(value);
            minFreq = 1;
            freqMap[1].push_front(key);
            node->it = freqMap[1].begin();
            cacheMap[key] = node;
        }
        else
        {
            cacheMap[key]->val = value;
        }
    }

代码清单: https://github.com/ShulinLiu/DataStructure-Algorithm/blob/master/LeetCode/LFUCache.hpp

以上就是LRU和LFU详解的全部内容。感谢关注。

你可能感兴趣的:([LeetCode] LRU和LFU详解之二)