本题解法代码的思想及编写参考了网址https://github.com/soulmachine/leetcode#leetcode题解题目
题目: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.
解析:使用双向链表(list)和哈希表(unordered_map),哈希表保存每个节点的地址,可以基本保证在 O(1) 时间内查找节点;双向链表插入和删除效率较高,单向链表插入和删除时,还要查找节点的前驱结点。具体实现细节:
1):越靠近链表头部,表示节点上次访问距离现在时间最短,尾部的节点表示最近访问最少;
2):访问节点时,如果节点存在,把该节点交换到链表头部,同时更新 hash 表中该节点的地址;
3):插入节点时,如果 cache 的 size 达到上限 capacity,则删除尾部节点,同时要在哈希表中删除对应的项,新节点插入链表头部
解题代码如下:
class LRUCache {
private:
struct CacheNode {
int value;
int key;
CacheNode(int v, int k) : value(v), key(k) {}
};
public:
LRUCache(int capacity) {
this -> capacity = capacity;
}
int get(int key) {
if (cacheMap.find(key) == cacheMap.end()) return -1;
// 把当前访问的节点移到链表头部,并且更新 map 中该节点的地址
cacheList.splice(cacheList.begin(), cacheList, cahceMap[key]);
cacheMap[key]= cacheList.begin();
return cacheMap[key] -> value;
}
void put(int key, int value) {
if (cacheMap.find(key) == cacheMap.end()) {
if (caceList.size() == capacity) { //删除链表尾部节点(最少访问的结点)
cacheMap.erase(cacheList.back().key);
cacheList.pop_back();
}
// 插入新节点到链表头部,并且在 map 中增加该节点
cacheList.push_front(CacheNode{value, key});
cacheMap[key] = cacheList.begin();
}
else {
//更新节点的值,把当前的访问的节点移到链表头部,并且
// 更新 map 中该节点的地址
cacheMap[key] -> value = value;
cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]);
cacheMap[key] = cacheList.begin();
}
}
private:
list<CacheNode> cacheList;
unordered_map<int, list<CacheNode>::iterator> cacheMap;
int capacity;
};