zoukankan      html  css  js  c++  java
  • 24. LFU缓存

    描述

    LFU是一个著名的缓存算法
    对于容量为k的缓存,如果缓存已满,并且需要逐出其中的密钥,则最少使用的密钥将被踢出。
    实现LFU中的set 和 get

    样例

    Input:
    LFUCache(3)
    set(2,2)
    set(1,1)
    get(2)
    get(1)
    get(2)
    set(3,3)
    set(4,4)
    get(3)
    get(2)
    get(1)
    get(4)
    

    Output:
    2
    1
    2
    -1
    2
    1
    4

    题解:

    class LFUCache {
    private:
        struct ListNode {
            int key;
            int value;
            ListNode* prev;
            ListNode* next;
            ListNode(int k, int v) : key(k), value(v), prev(NULL), next(NULL) {}; 
        };
        
        struct BucketNode {
            int freq;
            ListNode* head;
            ListNode* tail;
            BucketNode* prev;
            BucketNode* next;
            
            BucketNode(int f) : freq(f), prev(NULL), next(NULL), head(NULL), tail(NULL) {};
            
            void removeOne(ListNode* node) {
                if (node == head && node == tail) {
                    tail = head = NULL;
                } else if (node == head) {
                    node->next->prev = NULL;
                    head = node->next;
                } else if (node == tail) {
                    node->prev->next = NULL;
                    tail = node->prev;
                } else {
                    node->prev->next = node->next;
                    node->next->prev = node->prev;
                }
                node->prev = node->next = NULL;
            }
            
            void addOne(ListNode* node) {
                if (head == NULL) {
                    head = tail = node;
                } else {
                    head->prev = node;
                    node->next = head;
                    head = node;
                }
            }
            
            bool empty() { return head == NULL; }
        };
        
    public:
        LFUCache(int capacity) : mCapacity(capacity) {
            head = tail = NULL;
        }
        
        int get(int key) {
            if (mCapacity == 0) return -1;
            ListNode* node = promote(key);
            return node ? node->value : -1;
        }
        
        void set(int key, int value) {
            if (mCapacity == 0) return;
            
            ListNode* node = promote(key);
            if (node) {
                node->value = value;
                return;
            } else {
                if (freqTable.size() >= mCapacity) evictLast();
                node = new ListNode(key, value);
                BucketNode* bucket;
                if (tail == NULL || tail->freq != 1) {
                    bucket = new BucketNode(1);
                    bucket->addOne(node);
                    if (tail == NULL) {
                        head = tail = bucket;
                    } else {
                        bucket->prev = tail;
                        tail->next = bucket;
                        tail = bucket;
                    }
                } else {
                    bucket = tail;
                    bucket->addOne(node);
                }
                freqTable[key] = pair<BucketNode*, ListNode*>(bucket, node);
            }
        }
        
    private:
        inline ListNode* promote(int key) {
            auto it = freqTable.find(key);
            if (it == freqTable.end()) return NULL;
            BucketNode* bucket = it->second.first;
            ListNode* node = it->second.second;
            bucket->removeOne(node);
            BucketNode* newBucket;
            if (bucket->prev == NULL || bucket->prev->freq != bucket->freq + 1) {
                newBucket = new BucketNode(bucket->freq + 1);
                newBucket->addOne(node);
                if (bucket->prev == NULL) {
                    head = newBucket;
                    newBucket->next = bucket;
                    bucket->prev = newBucket;
                } else {
                    bucket->prev->next = newBucket;
                    newBucket->prev = bucket->prev;
                    newBucket->next = bucket;
                    bucket->prev = newBucket;
                }
            } else {
                newBucket = bucket->prev;
                newBucket->addOne(node);
            }
            
            it->second.first = newBucket;
            it->second.second = node;
            
            if (bucket->empty()) removeBucket(bucket);
            
            return node;
        }
        
        inline void removeBucket(BucketNode* bucket) {
            if (bucket == head && bucket == tail) {
                head = tail = NULL;
            } else if (bucket == head) {
                bucket->next->prev = NULL;
                head = bucket->next;
            } else if (bucket == tail) {
                bucket->prev->next = NULL;
                tail = bucket->prev;
            } else {
                bucket->prev->next = bucket->next;
                bucket->next->prev = bucket->prev;
            }
            delete bucket;
        }
        
        inline void evictLast() {
            ListNode* node = tail->tail;
            freqTable.erase(node->key);
            tail->removeOne(node);
            delete node;
            if (tail->empty()) removeBucket(tail);
        }
        
    private:
        int mCapacity;
        BucketNode* head;
        BucketNode* tail;
        unordered_map<int, pair<BucketNode*, ListNode*>> freqTable;
    };
    
  • 相关阅读:
    地址SQL文件
    SpringBoot webjars 映射
    Maven 阿里镜像
    Log4j输出的日志乱码问题
    Redis Client 官方下载地址
    SpringBoot连接Oracle报错,找不到驱动类,application.properties文件中驱动类路径为红色
    Linux Ubuntu 默认root密码
    Java 格式化字符串
    Linux Ubuntu 常见的压缩命令
    使用MD5比较两个文件是否相同
  • 原文地址:https://www.cnblogs.com/deepend/p/14199345.html
Copyright © 2011-2022 走看看