LRU 缓存
题目链接
个人思路
采用C++的容器,没有手撕双向链表
题意
实现LRU的初始化,读取,写入,分别对应LRUCache()、get()、put()
用到的理论和技术
- 双向链表list的插入、删除、访问、迭代器、auto关键字
- map,插入、删除、访问
- 类的初始化
- LRU机制
思路
LRU(Least Recently Used),最近最少使用算法,是页面置换算法的一种 也叫最近最久未使用算法 LRUCache():初始化内存的大小 get():获取内存中的数据,若不存在返回-1 put():向内存写入数据。
- 若数据存在,则更新并访问当前数据,表示当前使用过当前数据;
- 如果不存在
- 内存没有超限,则写入当前数据,表示当前使用过当前数据。
- 内存超限,删去最近最久未使用的数据,写入当前数据,表示当前使用过当前数据。
数据结构: 下文规定,哈希表map统称键值;输入数据统称key,val
- pair<int,int>:输入数据是key,val的形式,数据形式:key,val
- 双向链表List<pair<int, int> >,双向链表
- map<int, pair<int, int>::iterator>,mp[key]:map的键 == 数据的key,map的值 == 数据 key,val在双向链表中的迭代器
Q1:为什么要用链表 A:由于算法考虑到访问的顺序,因此需要使用链表 Q2:为什么要用双向量表 A:链表头部表示最近使用过,链表尾部表示最近未使用过,因此涉及到头部的插入和尾部的插入与删除 Q3:为什么要用map A:要保证常规时间内插入删除 Q4:为什么map的值是key-val对所在双向链表中的迭代器 A:便于list.erase(iter),在任意位置删除 Q5:既然哈希表中已经存了 数据的key,为什么链表中还要存数据key-val对呢,只存val不行么? A:当内存满了,双向链表末尾数据被删除,对应的哈希表中的旧数据也要删除,然而哈希表的删除是根据哈希表的值进行的,链表中只存数据的val,是无法找到对应数据的key
注意
个人思路代码
伪代码
HashMap<Integer, Node> map;
DoubleList cache;
int get(int key) {
if (key 不存在) {
return -1;
} else {
将数据 (key, val) 提到开头;
return val;
}
}
void put(int key, int val) {
Node x = new Node(key, val);
if (key 已存在) {
把旧的数据删除;
将新节点 x 插入到开头;
} else {
if (cache 已满) {
删除链表的最后一个数据腾位置;
删除 map 中映射到该数据的键;
}
将新节点 x 插入到开头;
map 中新建 key 对新节点 x 的映射;
}
}
class LRUCache {
private:
int cap;
list<pair<int, int> > cache;
unordered_map<int, list<pair<int, int> >::iterator> hash;
public:
LRUCache(int capacity) {
cap = capacity;
}
int get(int key) {
if(hash.count(key) == 0){
return -1;
}
else{
auto key_value = *hash[key];
cache.erase(hash[key]);
cache.push_front(key_value);
hash[key] = cache.begin();
return cache.front().second;
}
}
void put(int key, int value) {
if(hash.count(key) != 0){
cache.erase(hash[key]);
}
else{
if(cache.size() >= cap){
hash.erase(cache.back().first);
cache.pop_back();
}
}
cache.push_front({key, value});
hash[key] = cache.begin();
}
};
参考
作者:labuladong 链接:https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
|