运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get
和 写入数据 put
。
获取数据 get(key)
- 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value)
- 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4</pre>
思路:
get要O(1)必然用到哈希表,put功能是要维护历史数据,随时能够提取LRU的数据,要O(1)复杂度的话那必然要能够在常数时间内完成对数据的调整,即把使用的数据放一边,留下没使用过的数据,并且通过常数时间找到这个点,因此想到双向链表维护历史数据,并通过key与双向链表建立联系。每次put或者get把当前数据放在双向链表头指针的位置 ,删除元素时,释放尾指针即可。具体实现代码如下。
class LRUCache {
public:
struct node{
int key;
int val;
node* pre;
node* next;
node(int key2,int val2){key=key2;val=val2;pre=next=nullptr;}
};
class doublelinkedlist{
public:
node* pHead;
node* pTail;
int size;
doublelinkedlist()
{
pHead=pTail=nullptr;
size=0;
}
void addtofirst(node* n)
{
if(!pHead)
{
pHead=pTail=n;
}
else
{
n->next=pHead;
pHead->pre=n;
pHead=n;
}
size++;
}
void unlink(node* n)
{
node* pre=n->pre;
node* next=n->next;
if(n==pHead)
{
if(next)
{
next->pre=nullptr;
}
pHead=next;
}
else if(n==pTail)
{
if(pre)
{
pre->next=nullptr;
}
pTail=pre;
}
else
{
pre->next=next;
next->pre=pre;
}
size--;
}
void taketofirst(node* n)
{
unlink(n);
addtofirst(n);
}
void del(node* n)
{
unlink(n);
delete n;
}
};
LRUCache(int capacity) {
cap=capacity;
}
int get(int key) {
if(hashmap.find(key)!=hashmap.end())
{
dll.taketofirst(hashmap[key]);
return hashmap[key]->val;
}
return -1;
}
void put(int key, int value) {
if(hashmap.find(key)!=hashmap.end())
{
dll.taketofirst(hashmap[key]);
hashmap[key]->val=value;
}
else
{
node* n=new node(key,value);
hashmap[key]=n;
if(dll.size<cap)
{
dll.addtofirst(n);
}
else
{
hashmap.erase(dll.pTail->key);
dll.del(dll.pTail);
dll.addtofirst(n);
}
}
}
int cap;
map<int,node*> hashmap;
doublelinkedlist dll;
};
/**
* 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);
*/