1 需求分析
需求:
①O(1)时间访问任意key → 哈希表(unordered_map)
②O(1)时间删除LRU缓存中的键值对 → list
③O(1)时间向LRU缓存的头部增加/移动键值对 → list(不能使用vector,O(n)时间)
思路:
外层数据结构:hashtable,存储键值对的键,值维护指向链表中元素的指针
内存数据结构:双向链表,支持O(1)时间插入/删除/移动操作
注:应尽量使用STL自带的容器/数据结构。
2 实现代码
#include <iostream>
using namespace std;
#include <list>
#include <unordered_map>
class LRUCache {
public:
LRUCache(int capacity) {
_capacity = capacity;
}
int get(int key) {
//查询节点是否存在
const auto pos = _map.find(key);
if (pos == _map.end()) { //关键字key不存在缓存中
return -1;
}
else { //关键字key存在缓存中,刚刚已被查询,则移至LRU缓存的最前位置(不会被最先删除)
//list::splice(iterator position, list<T,Allocator>& x, iterator it);
//将链表对象x指定迭代器位置it的元素,拼接至position位置
_cache.splice(_cache.begin(), _cache, pos->second); //将节点移动至链表头
return pos->second->second; //返回关键字key对应的值
}
}
void put(int key, int value) {
//判断待插入的键值对,关键字key是否已存在缓存中
const auto pos = _map.find(key);
if (pos != _map.end()) { //关键字key已存在缓存中
//更新对应的值
pos->second->second = value;
//将更新后的键值对,移至链表头
_cache.splice(_cache.begin(), _cache, pos->second);
return;
}
else { //关键字key不存在缓存中
//若插入前已到达缓存容量,删除链表末尾的节点(最近最久未使用)
if (_cache.size() == _capacity) {
//获取链表末尾的节点
const auto& lastNode = _cache.back();
//从哈希表中删除节点信息(根据关键字key删除)
_map.erase(lastNode.first);
//从链表中删除末尾节点
_cache.pop_back();
}
//插入新的节点至链表头
_cache.push_front(make_pair(key, value));
//更新哈希表信息(关键字对应的值→链表的指针/迭代器位置)
_map[key] = _cache.begin();
}
}
private:
//缓存容量
int _capacity;
//存储键值对的链表(缓存)
list<pair<int, int>> _cache;
//哈希表-键和链表指针的映射关系 <关键字key, 链表元素的迭代器位置/指针>
unordered_map<int, list<pair<int, int>>::iterator> _map;
};
/**
* 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);
*/