LRU cache

https://leetcode.cn/problems/lru-cache/
设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构
配图全部来自于lc的题解

我门来看下图所示的数据结构

每个key对应着一个节点,每个节点存有key,value,prev,next。

我们现在将该图稍微改动一下,添加一个将表头和表尾去掉,换成一个哨兵节点dummy,并改成双向循环链表。就像下图一样

细节都有注释,直接看代码

//哈希将双向循环链表
//哈希每一个key对应的节点,每个节点存有key,value,prev,next

//每次执行get()或put()都算使用一次其参数对应的key值的关键字
//要将其从原来位置删除然后重新头插进来

//最久未使用的关键字就是链表尾部的关键字

struct Node
{
    int key,value;
    Node*prev,*next;

    Node(int k = 0,int v = 0) : key(k) , value(v) {}
};

class LRUCache {
private:
    int capacity; //容量
    int cnt = 0; //当前节点数量。一定要记得初始化
    Node*dummy; //哨兵节点
    unordered_map<int,Node*>h;  //每个key对应一个节点
public:
    LRUCache(int capacity) : capacity(capacity) , dummy(new Node()) {
        dummy->next = dummy->prev = dummy;  //双向循环链表
    }
    
    int get(int key) {
        if(h[key] == nullptr) return -1; //哈希值为空,关键字key不在缓存中
        auto node = h[key]; 
        node->next->prev = node->prev; //删除这个节点
        node->prev->next = node->next;

        dummy->next->prev = node;      //头插当前节点
        node->next = dummy->next;
        node->prev = dummy;
        dummy->next = node;

        h[key] = node;              //要记得更新h[key]
        return node->value;
    }
    
    void put(int key, int value) {
       Node *node;
       if(h[key]!=nullptr)  //若key存在,将节点删除
       {
           h[key]->value = value;
           node = h[key];
           node->next->prev = node->prev; //删除当前节点
           node->prev->next = node->next;
       }
       else //若key不存在,则新建一个节点
       {
           node = new Node(key,value);
           h[key] = node;  
           cnt++;
       }
       dummy->next->prev = node;  //不管key在不在,都头插节点
       node->next = dummy->next;
       node->prev = dummy;
       dummy->next = node;
       if(cnt > capacity) //若当前节点数量超过容量,将链表尾部节点删除
       {
           node = dummy->prev;
           h[node->key] = nullptr;
           dummy->prev = node->prev;
           node->prev->next = dummy;
           cnt--;
       }
    }
};

posted @ 2024-03-02 20:39  拾墨、  阅读(4)  评论(0编辑  收藏  举报