文章目录
- 1.题目
- 2.代码
1.题目
- 题目要求
- 思路:
(1)为了使得查找、插入和删除都有较高的性能,使用一个双向链表std::list和哈希表std::unordered_map;
哈希表保存每个节点的地址,基本可以保证O(1)的时间
(2)较于单向链表,双向链表插入和删除效率高
(3)越靠近链表头部,表示节点上次访问距离现在时间越短,尾部的节点说明距离现在时间最长
(4)访问节点时,若节点存在,则把该节点交换到链表头部,同时更新hash表中该节点的地址
(5)插入节点时,若cache的size达到了上限capacity,则删除尾部节点,同时要在hash表中删除对应的项;
(6)新节点插入链表头部
(7)这里我们使用 C++ STL 中的函数 splice,专门移动链表中的一个或若干个结点到某个特定的位置,这里我们就只移动 key 对应的迭代器到列表的开头 - eg:
LRUCache cache = new LRUCache( 2 /* capacity */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // returns 1
cache.put(3, 3); // evicts key 2
cache.get(2); // returns -1 (not found)
cache.put(4, 4); // evicts key 1
cache.get(1); // returns -1 (not found)
cache.get(3); // returns 3
cache.get(4); // returns 4
2.代码
class LRUCache{
public:
LRUCache(int cap)
{
this->cap=cap;
}
int get(int key)
{
if (hashmap_list.find(key) == hashmap_list.end())
return -1;
把当前访问的节点移动到链表头部,且更新map中该节点的地址
Cachelist.splice(Cachelist.begin(),Cachelist,hashmap_list[key]);
hashmap_list[key]=Cachelist.begin();
return hashmap_list[key]->value;
}
void put(int key,int value)
{
if (hashmap_list.find(key) == hashmap_list.end())
{
删除链表尾部的节点
if (Cachelist.capacity() == cap)
{
Cachelist.pop_back(Cachelist.back());
hashmap_list.erase(Cachelist.back()->key);
}
插入新节点到链表头部,且在map中增加该节点
Cachelist.push_front(CacheNode(key,value));
hashmap_list[key]=Cachelist.begin();
}
else
{
更新节点的值,把当前访问的节点移动到链表头部,且更新map中该节点的地址
hashmap_list[key]->value=vaule;
Cachelist.splice(Cachelist.begin(),Cachelist,hashmap_list[key]);
hashmap_list[key]=Cachelist.begin();
}
}
private:
struct CacheNode{
int key;
int value;
CacheNode(int key, int value) : key(key), value(value) {}
}CacheNode;
list<CacheNode> Cachelist;
unordered_map<int,list<CacheNode>::iterator> hashmap_list;
int cap;
};