主要思路:
假设缓存有固定容量,在缓存头部的意味着是最近最久没使用的可以丢弃,在缓存尾部是刚刚使用过的
对于读取缓存:get操作 (有则读取,并将该内容放到缓存尾部,代表刚刚使用;无则返回固定的值)
对于写入缓存:put操作(有则更新,并将内容放到缓存尾部,代表刚刚使用;无则判断容量是否满,没满直接插入,满了就删除缓存头部再插入)
这里想要两者都是O(1)的时间复杂度,可以考虑通过
一个双向链表list和一个unordered_map以及一个最大容量max来实现
其中list存储键值对,unordered_map存储键及其对应的迭代器
class LRUCache {
public:
LRUCache(int capacity) {
max=capacity;
}
int get(int key) {
if(re.find(key)==re.end())//没有则返回-1
return -1;
else //有则返回,并且插入到链表尾部
{
lru.push_back({key, (*re[key]).second});//插入新的节点
lru.erase(re[key]);//删去旧的节点
re[key]=--lru.end();
//cout<<*re[key];
return (*re[key]).second;
}
}
void put(int key, int value) {
if(re.find(key)==re.end())//没有则
{
if(lru.size()>=max)//map和list中都需要删除
{
re.erase(lru.front().first);
lru.pop_front();
}
lru.push_back({key,value});
re[key]=--lru.end();
}
else
{
lru.erase(re[key]);//删去旧的节点
lru.push_back({key,value});
re[key]=--lru.end();
}
}
private:
int max=0; //最大容量
list<pair<int,int> > lru;//按访问的时间顺序存储
unordered_map<int, list<pair<int,int> >::iterator> re;//如果get则放到链表的末尾,put时判断容量,不够则删除链表的头部
//本来计划记录每个节点使用的频率,但还需要排序,这不太现实
};
/**
* 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);
*/