题目
请你设计并实现一个满足 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) 的平均时间复杂度运行。
思路
- 使用双向链表维护缓存的使用顺序,最近使用的节点在链表的头部,最久未使用的节点在链表的尾部。
- 使用哈希表快速定位缓存中的节点,通过键找到对应的链表节点。
思路
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std;
// 定义双向链表结构
struct DLinkedNode
{
int key;
int value;
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:
unordered_map<int, DLinkedNode*> cache;
DLinkedNode* head;
DLinkedNode* tail;
int size;
int capacity;
public:
LRUCache(int capacity);
int get(int key);
void put(int key, int value);
void removeNode(DLinkedNode* Node);
void insertHead(DLinkedNode* Node);
};
LRUCache::LRUCache(int _cacapacity) : capacity(_cacapacity),size(0)
{
// 初始化双向链表
head = new DLinkedNode();
tail = new DLinkedNode();
head->next = tail;
tail->prev = head;
}
void LRUCache::removeNode(DLinkedNode* Node)
{
auto pre = Node->prev;
auto next = Node->next;
pre->next = next;
next->prev = pre;
}
void LRUCache::insertHead(DLinkedNode* Node)
{
auto pre = head;
auto next = head->next;
// 从左向右
pre->next = Node;
Node->next = next;
// 从右向左
next->prev = Node;
Node->prev = head;
}
// 获取缓存中的元素
// head 1 2 3 5 tail
int LRUCache::get(int key)
{
if (!cache.count(key))
{
return -1;
}
// 从链表中移除元素
auto Node = cache[key];
removeNode(Node);
// 将访问元素插入到最前面
insertHead(Node);
return Node->value;
}
void LRUCache::put(int key, int value)
{
//key不存在情况
if (!cache.count(key))
{
//创建新节点
auto newNode = new DLinkedNode(key, value);
// 添加到cache中
cache[key] = newNode;
// 最新访问添加到头部
insertHead(newNode);
++size;
if (size > capacity)
{
// 删除尾节点和对应的key
auto oldNode = tail->prev;
removeNode(oldNode);
cache.erase(oldNode->key);
delete oldNode;
--size;
}
}
else
{
auto oldNode = cache[key];
oldNode->value = value;
insertHead(oldNode);
}
}
int main()
{
LRUCache lruCache(2);
lruCache.put(1, 1);
lruCache.put(2, 2);
cout << "Get 1: " << lruCache.get(1) << endl;
lruCache.put(3, 3);
cout << "Get 2: " << lruCache.get(2) << endl;
lruCache.put(4, 4);
cout << "Get 1: " << lruCache.get(1) << endl;
cout << "Get 3: " << lruCache.get(3) << endl;
cout << "Get 4: " << lruCache.get(4) << endl;
return 0;
}