problem:
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get
and set
.
get(key)
- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value)
- Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
thinking:
(1)这道题我自己借助unordered_map和list实现了一个版本,小数据测试通过,大数据测试时(连续set、get),由于频繁的操作map、list,超时了。
最高效的做法是将list嵌入到节点的结构体中。
我的思路:构建一个包含key值和访问次数visited的结构体,每次访问结构体对象时,访问次数+1,在节点数未达到上限时,将新节点插入到list的头部。在达到上限时,
将访问次数最小的节点移到list的末尾,移除尾部节点,在list头部插入新的节点。使用unordered_map提高超找效率。
code:
class node{
public:
int _key;
int _visited;
node(int key, int visited):_key(key),_visited(visited){}
};
class LRUCache{
private:
unordered_map<int,list<node *>::iterator> map_record;
list<node *> list_record;
int size;
public:
LRUCache(int capacity) {
size=capacity;
}
int get(int key) {
if(map_record.count(key)!=0)
{
unordered_map<int,list<node *>::iterator>::iterator it_a=map_record.find(key);
list<node *>::iterator it_b=it_a->second;
node *node_tmp=*it_b;
node_tmp->_visited+=1;
adjust();
return key;
}
else
return -1;
}
void set(int key, int value) {
if(map_record.count(key)!=0)
{
unoredered_map<int,list<node *>::iterator>::iterator it_a=map_record.find(key);
list<node *>::iterator it_b=it_a->second;
node *node_tmp=*it_b;
node_tmp->_key=value;
node_tmp->_visited+=1;
}
else
{
if(list_record.size()<size)
{
node *tmp_node=new node(value,1);
list_record.push_front(tmp_node);
list<node *>::iterator it=find(list_record.begin(),list_record.end(),tmp_node);
map_record.insert(make_pair(value,it));
}
else
{
adjust();
node *tmp_node=new node(value,1);
list_record.push_front(tmp_node);
map_record.clear();
for(list<node *>::iterator it=list_record.begin();it!=list_record.end();++it)
{
node *tmp=*it;
map_record.insert(make_pair(tmp->_key,it));
}
}
}
}
protected:
void adjust()
{
if(list_record.empty())
return;
node *index=list_record.back();
list<node *>::iterator min_it;
int min_visited=index->_visited;
for(list<node *>::iterator it=list_record.begin();it!=list_record.end();++it)
{
node *tmp_node = *it;
if(tmp_node->_visited<min_visited)
min_it=it;
}
list<node *>::iterator last=list_record.end();
swap(min_it,--last);
list_record.pop_back();
}
};
一个高效且测试通过的版本:
struct CacheNode {
int key;
int value;
CacheNode* next;
CacheNode* prev;
CacheNode(int _key, int _value) {
key = _key;
value = _value;
next = nullptr;
prev = nullptr;
}
};
class LRUCache{
public:
LRUCache(int capacity) {
_capacity = capacity;
head = new CacheNode(INT_MIN,-1);
tail = head->next;
len = 0;
}
int get(int key) {
auto found = cache.find(key);
if (found != cache.end()) {
if (found -> second == tail) {
tail = tail->prev;
}
insertToHead(found->second);
if (tail == head) tail = head -> next;
return found -> second -> value;
}
return -1;
}
void set(int key, int value) {
auto found = cache.find(key);
if (found != cache.end()) {
found->second->value = value;
if (found -> second == tail) {
tail = tail->prev;
}
insertToHead(found->second);
if (tail == head) tail = head->next;
return ;
}
if (len == _capacity) {
CacheNode* tmp = tail -> prev;
cache.erase(tail->key);
deleteNodeLink(tail);
delete tail;
tail = tmp;
insertToHead(new CacheNode(key, value));
return ;
}
insertToHead(new CacheNode(key, value));
if (tail == nullptr) tail = head->next;
len++;
}
private:
CacheNode* head;
CacheNode* tail;
int _capacity;
int len;
unordered_map<int, CacheNode*> cache;
void deleteNodeLink(CacheNode* node) {
CacheNode* prev = nullptr;
CacheNode* next = nullptr;
if (node -> prev) prev = node->prev;
if (prev) {
prev -> next = node -> next;
}
if(node->next) next = node -> next;
if(next) {
next -> prev = prev;
}
}
void insertToHead(CacheNode* node) {
deleteNodeLink(node);
node->prev = head;
node->next = head->next;
if (head -> next) head->next->prev = node;
head->next = node;
cache[node->key] = node;
}
};