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--;
}
}
};