LeetCode 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 ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 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

思路:题目要求我们实现两个功能1.get查询功能,put删除功能(如果容器内的数达到容量 capacity,则删除最久未用的那个变量),需要注意的是,这里的最久未被被查询是怎么定义的?就像

原本指南针这个应用是再队列的最后一位,当我打开他一次后,他就跑到前面了,另外假设容器的容量为4,我再打开一个新的应用,那么,在最后一位的计算器就要被关掉。

普通的队列可以根据元素被压入的时间进行排序,但不能访问队列中间的元素,也不能提出,哈希表可以实现查询功能,但不能实现按照元素被访问时间进行排序,如果我们把他们结合起来,组成哈希链表,既有了哈希表的查询功能,也有了链表的先后顺序功能。这里采用的是双向链表

代码如下,逻辑比较简单,主要是函数的调用。

cpp 复制代码
struct DLinkedNode {//双向链表的节点
    int key, value;//两个存变量的int变量
    DLinkedNode* prev;//指向上个节点
    DLinkedNode* next;//指向下个节点
    DLinkedNode() :key(0), value(0), prev(nullptr), next(nullptr){}//初始化节点的函数
    DLinkedNode(int _key,int _value):key(_key),value(_value),prev(nullptr),next(nullptr){}
};
class LRUCache {
private://这个是声明变量再class外面和内部都可访问
    unordered_map<int, DLinkedNode*>cache;//
    DLinkedNode* head;//创建头节点
    DLinkedNode* tail;//创建尾节点
    int size;//统计链表内有多少个节点
    int capacity;//容器容量
    /*public: 是一个访问说明符(access specifier),它用于指定类的成员(成员变量或成员函数)在类外部是否可见和可访问。public 成员可以从任何地方被访问,包括类的外部和其他文件中的代码。*/
public:
    LRUCache(int _capacity) : capacity(_capacity), size(0) {//这一步是为两个变量赋值
        head = new DLinkedNode();//创建两个空节点
        tail = new DLinkedNode();
        head->next = tail;
        tail->prev = head;

       
    };
    int get(int key) {
        if (!cache.count(key))//看看这个变量在不在队列当中
        {
            return -1;
        }
        //如果在队列当中。将他提到队列头部
        DLinkedNode* node = cache[key];
        moveToHead(node);
        return node->value;
    }
    void put(int key, int value) {
        if (!cache.count(key))
        {
            //如果不存在,创建一个新节点,压入哈希表
            DLinkedNode* node = new DLinkedNode(key, value);
            cache[key] = node;
            // 添加至双向链表的头部
            addToHead(node);//
            ++size;
            if (size > capacity)
            {
                DLinkedNode* removed = removeTail();//删除尾部节点
                // 删除哈希表中对应的项
                cache.erase(removed->key);//使用 erase 方法来删除 map 中的单个元素
                // 防止内存泄漏
                delete removed;
                --size;
            }
        
        }
        else {
            //如果存在,先定位节点的位置
            DLinkedNode* node = cache[key];
            node->value = value;//更改值
            addToHead(node);//将其移动到前面
        }
    }
    void addToHead(DLinkedNode* node)//将节点指向头节点
    {
        node->prev = head;//指向头结点
        node->next = head->next;//node节点指向未插入之前头节点的下一个节点
        head->next -> prev = node;//调整未插入之前头结点的下一个节点,指向node
        head->next = node;
    }
    void removeNode(DLinkedNode* node) {//这个函数用于从双向链表中移除一个节点
        node->prev->next = node->next;//前一个结点的next指向下一个节点
        node->next->prev = node->prev;//后一个节点的perv
   
    }
    void moveToHead(DLinkedNode* Node) {//将一个节点移动到头部
        removeNode(Node);//删除这个节点
        addToHead(Node);//将这个节点移动到头节点
    }

    DLinkedNode* removeTail() {//这个函数的作用是移除链表尾部的节点并返回他的值
        DLinkedNode* node = tail->prev;
        removeNode(node);
        return node;
    }


};
相关推荐
Code_Solitude23 分钟前
c语言:二分法的完整补充
c语言·开发语言·算法
一切皆是因缘际会24 分钟前
掌控信息论:同源星际通信基础理论
人工智能·算法·ai
ShineWinsu2 小时前
对于Redis:事务的解析
数据库·redis·mysql·缓存·面试·事务·acid
List<String> error_P2 小时前
freertos数据结构--链表
数据结构·链表
JavaPub-rodert2 小时前
公共 Docker 镜像源总失效?用 Harbor Proxy Cache 自建 Docker Hub 镜像缓存
java·缓存·docker
动词ing3 小时前
【C语言题目练习】算法 整数反转
c语言·开发语言·算法
Nil2083 小时前
leetcode 55跳跃游戏
算法·leetcode·游戏
longlongzihan3 小时前
LeetCode 128. 最长连续序列 —— 从排序到哈希集合
数据结构·c++·算法·leetcode·排序算法·哈希表
mmmmath_33 小时前
二叉树の一些知识
数据结构·算法
DongQiShanRen3 小时前
裁决台账双向互校(下):台账哈希链、三向对账与最小落地
人工智能·深度学习·算法·目标跟踪·自然语言处理·rust·哈希算法