参考:
https://leetcode.com/problems/lru-cache/discuss/46223/O(1)-unordered_map-%2B-list-%2B-splice
用双向链表+哈希表实现
双向链表的节点为插入的元素,实现高效率的删除和移动操作
哈希表key为元素的key,值为元素节点在队列中的指针,实现高效率的查找操作
取元素:
不存在直接返回,存在时需要将对应节点移动到队列头,然后返回节点的值
放元素:
该元素之前不存在
队列没满,将元素插入队列头,同时加入哈希表
队列满了,删除队尾元素,哈希表也删除对应元素,然后将新元素加入队列头和哈希表中
该元素之前存在
更新节点值,将节点移动到队头
class LRUCache {
private:
// A list of (key, value) pairs
list<pair<int, int>> items; //存放节点,每个节点包含key和value,链表头部是最近用的。尾部是最近没用的
// Map items to iterators (pointers) to list nodes
unordered_map<int, list<pair<int, int>>::iterator> cache; //key为元素的键,value为元素节点的指针
// The capacity of the list
int capacity;
public:
LRUCache(int capacity) : capacity(capacity) {}
int get(int key) {
// If key is not found in hash map, return -1
if (cache.find(key) == cache.end()) //不存在
return -1;
// Move the (key, value) pair to the beginning of the list
items.splice(items.begin(), items, cache[key]); //将items里cache[key]所指元素移动到items的头部
return cache[key]->second;
}
void put(int key, int value) {
// The key is not in the hash table
if (cache.find(key) == cache.end()) { //如果要加入的元素之前不存在
// If the cache is full then delete the least recently
// used item, which is at the end of the list
if (items.size() == capacity) { //如果队列满了
cache.erase(items.back().first); //删除队尾的元素对应的哈希表中的值
items.pop_back(); //删除队列中的值
}
items.push_front(make_pair(key, value)); //放入队头
cache[key] = items.begin(); //加入哈希表
} else { //要加入的元素之前存在
// Update the value associated with the key
cache[key]->second = value; //更新值
// Move the (key, value) pair to the beginning of the list
items.splice(items.begin(), items, cache[key]); //将该元素移动到队头
}
}
};
//代码里的splice()函数可以用先删除该元素,再在链表头插入来代替
不用splice函数的做法,其实和上面的方法一样,略看即可
参考:
https://leetcode.com/problems/lru-cache/discuss/45976/C%2B%2B11-code-74ms-Hash-table-%2B-List
class LRUCache {
private:
int capacity;
list<int> recent; //按顺序存放最近用过的元素,队首最近用过,队尾最近没用过
unordered_map<int, int> cache; //存放插入的节点
unordered_map<int, list<int>::iterator> pos; //存放节点和其在链表中的位置
void use(int key) {
if (pos.find(key) != pos.end()) {
recent.erase(pos[key]);
} else if (recent.size() >= capacity) {
int old = recent.back();
recent.pop_back(); //将该节点删除
cache.erase(old);
pos.erase(old);
}
recent.push_front(key); //将该节点插入队首
pos[key] = recent.begin();
}
public:
LRUCache(int capacity): capacity(capacity) {}
int get(int key) {
if (cache.find(key) != cache.end()) {
use(key);
return cache[key];
}
return -1;
}
void set(int key, int value) {
use(key);
cache[key] = value;
}
};