• 链表-LRU缓存


    请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
    实现 LRUCache 类:
    LRU是Least Recently Used的缩写,意为“最近最少使用”。LRU是一种常用的缓存淘汰策略,用于管理缓存中的数据。

    举个例子,你从一堆书中找出自己想要看的书,读完之后一般是放在最上面;如果你又从其他地方拿了一本书读完之后,打算放入这堆书中,如果这堆书中还有同名书,只是年份不同,那么就用这本书进行替换,如果没有同名书,由于“空间”不够使用,只能将最底下的书移走,再放入这本书

    LRU缓存算法的基本思想是:当缓存空间不足时,优先淘汰最近最少使用的数据,以便为新数据腾出空间。具体来说,LRU算法会维护一个有序列表,列表中的元素按照访问时间从新到旧排列。每当缓存命中时,就将命中的数据移动到列表的头部,每当缓存缺失时,就将新数据插入到列表的头部,并将列表尾部的数据淘汰掉。

    LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
    int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。

    void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。

    如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

    函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

    由于题目要求O(1)复杂度,采取双链表,每个节点都是一本书;使用哈希来快速查找书籍

    先创建节点Node

    struct Node{
        int _key;
        int _value;
        Node* _next;
        Node* _prev;
        Node(int key, int value): _key(key), _value(value), _next(nullptr), _prev(nullptr){}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    刚开始时,使用一个哨兵节点

    class LRUCache {
    private:
        Node* _dummy;
        int _capacity;
        unordered_map<int, Node*> _map;
        
    public:
        LRUCache(): _dummy(new Node(-1, -1)), _capacity(0){
            _dummy->_next = _dummy;
            _dummy->_prev = _dummy;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    实现查找书

        Node* get_node(int key)//查找书
        {
            auto it=_map.find(key);
            if(it==_map.end())//没找到
                return nullptr;
            auto node=it->second;//找到了
            remove(node);//从书堆中取出
            insert_to_head(node);//放在书顶
            return node;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    实现将书从书堆中移除

        void remove(Node* node)//从书堆中移除
        {
            node->_prev->_next = node->_next;
            node->_next->_prev = node->_prev;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现将书放入书顶

        void insert_to_head(Node* node)//放入书顶
        {
            node->_next = _dummy->_next;
            node->_prev = _dummy;
            _dummy->_next->_prev = node;
            _dummy->_next = node;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    实现取书get功能

        int get(int key)
        {
            auto node=get_node(key);//查找这本书
            return node?node->_value:-1;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现放入put功能

        void put(int key, int value)
        {
            auto node = get_node(key);
            if(node)//书堆中已经存在,进行替换
            {
                node->_value=value;
                return;
            }
            _map[key]=node=new Node(key, value);
            insert_to_head(node);//独一份,放入书顶
            if(_map.size()>_capacity)
            {
                auto node=_dummy->_prev;
                remove(node);
                _map.erase(node->_key);
                delete node;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    完整代码

    struct Node{
        int _key;
        int _value;
        Node* _next;
        Node* _prev;
        Node(int key, int value): _key(key), _value(value), _next(nullptr), _prev(nullptr){}
    };
    
    class LRUCache {
    private:
        Node* _dummy;
        int _capacity;
        unordered_map<int, Node*> _map;
    
        void remove(Node* node)//从书堆中移除
        {
            node->_prev->_next = node->_next;
            node->_next->_prev = node->_prev;
        }
    
        void insert_to_head(Node* node)//放入书顶
        {
            node->_next = _dummy->_next;
            node->_prev = _dummy;
            _dummy->_next->_prev = node;
            _dummy->_next = node;
        }
    
        Node* get_node(int key)//查找书
        {
            auto it=_map.find(key);
            if(it==_map.end())//没找到
                return nullptr;
            auto node=it->second;//找到了
            remove(node);//从书堆中取出
            insert_to_head(node);//放在书顶
            return node;
        }
    
    public:
        LRUCache(): _dummy(new Node(-1, -1)), _capacity(0){
            _dummy->_next = _dummy;
            _dummy->_prev = _dummy;
        }
    
        int get(int key)
        {
            auto node=get_node(key);//查找这本书
            return node?node->_value:-1;
        }
    
        void put(int key, int value)
        {
            auto node = get_node(key);
            if(node)//书堆中已经存在,进行替换
            {
                node->_value=value;
                return;
            }
            _map[key]=node=new Node(key, value);
            insert_to_head(node);//独一份,放入书顶
            if(_map.size()>_capacity)
            {
                auto node=_dummy->_prev;
                remove(node);
                _map.erase(node->_key);
                delete node;
            }
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
  • 相关阅读:
    pyqt5:pandas 读取 Excel文件或 .etx 电子表格文件,并显示
    [Redis]Zset类型
    使用html+css实现一个静态页面【传统文化茶带音乐6页】HTML学生个人网站作业设计
    LeetCode算法题解(动态规划)|LeetCoed62. 不同路径、LeetCode63. 不同路径 II
    pytorch笔记 GRUCELL
    iOS 登录分享推送支付问题
    【Mongodb-01】Mongodb亿级数据性能测试和压测
    HarmonyOS 3.1 第三方包导入
    ts-面向对象
    通用结构化剪枝DepGraph
  • 原文地址:https://blog.csdn.net/qq_68006585/article/details/138198765