请你设计并实现一个满足 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)
的平均时间复杂度运行。
要求复杂度达到O1,用哈希和双向链表
get方法,先看key存在不,不存在返回-1;存在了把他放到头部,返回结果
put方法,先看key存在不,存在,修改key对应的value,把key放到头部,这一步直接调get方便;如果不存在,看缓存满了没,满了就删除一直没用的,因此每次我们都把新用的放在了头部,因此没用的肯定就是最后一个,所以就删掉最后一个,把要新添加的加在头部
掌握list的splice方法
void splice (iterator position, list& x, iterator i);
简单来说就是把x
这个list
的i
处元素插入到position
的位置
下面是手撕代码:直接用了list,你也可以自己写一个双链表
class LRUCache {
//双链表和哈希实现o1的插入删除查找
//list和unordered_map底层是哈希表操作是o1
//list记录kv,map映射k和list迭代器实习o1的访问list元素
public:
int size;
list<pair<int,int>>li;
unordered_map<int,list<pair<int,int>>::iterator>map;
LRUCache(int capacity):size(capacity) {
}
int get(int key) {
if(map.find(key)==map.end())return -1;//没找到key
else//key存在,把他放到头部,返回
{
/* auto it=*map[key];
li.erase(map[key]);
li.push_front(it);
map[key]=li.begin();*///要知道list的splice,不然就得这么写,效率也不高
li.splice(li.begin(),li,map[key]);
return map[key]->second;
}
}
void put(int key, int value) {
if(get(key)!=-1){//key存在,因为调用了get,顺便也把他放到了头部
map[key]->second=value;//只用修改map的信息就行
}
else{//key不存在
if(size==li.size())//缓存满了,要删除不用的
{
map.erase(li.back().first);
li.pop_back();
}
li.push_front({key,value}); //添加新的key
map[key]=li.begin();
}
}
};
不借助stl,自己实现双向循环列表去使用
struct listnode
{
int key;
int val;
listnode*next;
listnode*pre;
listnode(int k=-1,int v=-1):key(k),val(v),next(nullptr),pre(nullptr){};
};
class LRUCache {
private:
listnode*vmhead;
listnode*vmtail;
int size=0;
int cap;
unordered_map<int,listnode*>mp;
public:
LRUCache(int capacity):cap(capacity) {
vmhead=new listnode();
vmtail=new listnode();
size=0;
vmhead->next=vmtail;
vmtail->pre=vmhead;
}
int get(int key) {
if(mp.count(key))
{
//存在
listnode*node=mp[key];
removenode(node);
return node->val;
}
//不存在
return -1;
}
void put(int key, int value) {
if(get(key)==-1)//不存在
{
listnode*node=new listnode(key,value);
if(size>=cap){
//满了
deletetail();
}
//没满
++size;
inserthead(node);
mp[key]=node;
}
else{
//存在
mp[key]->val=value;
}
}
//头插
void inserthead(listnode*node)
{
vmhead->next->pre=node;
node->next=vmhead->next;
vmhead->next=node;
node->pre=vmhead;
}
//尾删除
void deletetail()
{
mp.erase(vmtail->pre->key);
deletenode(vmtail->pre);
}
//删结点
void deletenode(listnode*cur)
{
cur->pre->next=cur->next;
cur->next->pre=cur->pre;
}
//指定结点移动到头部
void removenode(listnode*cur)
{
deletenode(cur);//删结点
inserthead(cur);//头插
}
};
/**
* 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);
*/