链表OJ(十六)146. 模拟LRU 缓存 双向链表+哈希

146. LRU 缓存

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

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

示例:

复制代码
输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4
cpp 复制代码
struct Node {
    Node* next;            出错点1:把指针定义成了 int*
    Node* pre;
    int key;
    int value;
    Node(int k = 0, int v = 0) {
        key = k;
        value = v;
        next = nullptr;
        pre = nullptr;
    }
};

class LRUCache {
private:
    int capacity;
    Node* dummy = new Node();
    unordered_map<int, Node*> hash_node;

    // 在链表中寻找结点
    Node* Find_Node(int key) {
        if (hash_node.find(key) != hash_node.end()) {
            return hash_node[key];
        } else
            return dummy;
    }

    // 将该cur元素移动至末尾
    void Get_back(Node* cur) 
    {
        cur->pre = dummy->pre;
        dummy->pre->next = cur;
        dummy->pre = cur;
        cur->next = dummy;    
                                            出错点2:忘记给哈希表中进行处理
        // 插入元素的时候也要给哈希表中进行插入    
        hash_node.insert(pair<int, Node*> (cur->key, cur));
    }

    void Delete_Node(Node* cur)
    {
        cur->next->pre = cur->pre;
        cur->pre->next = cur->next;

        // 删除元素的时候也要给哈希表中进行删除
        hash_node.erase(cur->key);
    }

public:
    LRUCache(int c) : capacity(c) {
        dummy->pre = dummy;
        dummy->next = dummy;
    }

    int get(int key) {
        // 1、在双向链表中找到这个元素
        Node* cur = Find_Node(key);
        if (cur != dummy) {
            // 2、更新这对元素到末尾位置
            Delete_Node(cur);
            Get_back(cur);
            return cur->value;              出错点3:指针的访问使用箭头......
        }
        return -1;
    }

    void put(int key, int v) {
        // 1、在双向链表中寻找这个元素
        Node* cur = Find_Node(key);
        
        if (cur != dummy) {
            // 2、如果已经存在,则修改它的value,并尾插
            Delete_Node(cur);
            cur->value = v;
            Get_back(cur);
        }
        else
        {
            // 3、不存在的话,尾插这个新元素对
            cur = new Node(key, v);
            Get_back(cur);
            capacity--;
            if(capacity < 0)
            {
                // 在有新插入情况下,访问容量是否大于capacity,如果超过,头删一个元素。
                Delete_Node(dummy->next);
                capacity++;
            }
        }
    
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */
相关推荐
土豆.exe12 小时前
Fastjson2 2.0.53 哈希碰撞 RCE:从原理到三种打法
算法·哈希算法
梅孔立13 小时前
两种免费的翻译API调用方式详解 - Edge官方API与个人缓存服务
前端·缓存·edge
gwf21613 小时前
SSD读写速度深度解析:顺序读写vs随机读写、IOPS、延迟,你的硬盘性能到底怎么看?
git·嵌入式硬件·缓存·github·智能硬件
番茄炒鸡蛋加糖15 小时前
缓存三大问题
缓存
江晓鱼未暖20 小时前
十七、Redis 核心原理与架构详解
大数据·数据库·数据仓库·redis·缓存·架构
小罗水20 小时前
第13章 Redis 缓存、幂等锁与任务状态
数据库·redis·缓存
热心市民lcj21 小时前
Spring Boot 整合 Caffeine 本地缓存实战
spring boot·后端·缓存
zx1154501 天前
【热点 Key 探测与加长缓存 TTL 实战】
缓存
海绵天哥1 天前
LeetCode Hot 100 | 链表(下)· 分组翻转与设计(C++ 题解)
c++·leetcode·链表
toooooop81 天前
如何用 ss + ps 精准定位本机 Redis 的“隐形”消费者?
linux·数据库·redis·缓存