刷题链接:LRU缓存机制
题目
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
- LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
示例
LRU 算法实际上是让你设计数据结构:首先要接收一个 capacity 参数作为缓存的最大容量,然后实现两个 API,一个是 put(key, val) 方法存入键值对,另一个是 get(key) 方法获取 key 对应的 val,如果 key 不存在则返回 -1。
我们要使时间复杂度为o(1),就要让插入、查询的时间复杂度都为o(1)。那么查询时间复杂度为o(1),首先想到哈希表;在数组中尾插、尾删的时间复杂度为o(1),但是在其他位置插入、删除就不是,所以我们在这里使用双链表。
在这里我们使用unorder_map以及STL中的list结构共同完成。 unordered_map用来查询,list用来存储。在unordered_map中存储的是list节点的迭代器,这样一方面可以直接查询到value,一方面可以直接拿到对应节点的迭代器,可以对list中的节点直接操作;若unordered_map中存储的是<key,value>结构,那么还需要遍历list才能找到具体节点,进行操作,时间复杂度就为o(n)。下面是unordered_map存储的结构:
unorder_map<key, list<key, value>::iterator>
图解:
list设计中,头部是最久未使用节点,尾部是最近刚使用节点。代码设计:
插入:
1.在unordered_map表中可以查询到插入的信息
- 获取到list节点,修改value值;因为是最近刚使用的节点,将这个节点移到list尾部
2.在unordered_map表中可以查询不到插入的信息
- 若缓存不满时,直接在list尾部插入,在unordered_map表中添加信息;
- 若缓存满了,则将最久未使用(list头部节点)删除,删除unordered_map表相关信息,然后在list尾部插入,在unordered_map表中添加信息;
获取:
- 若获取某一节点值,通过unordered_map表,找到list节点的迭代器,获取value值;因为是最近刚使用节点,将此节点移到list尾部
具体代码:
class LRUCache {
public:
typedef list<pair<int, int>>::iterator LIST_ITER; //链表迭代器
LRUCache(int capacity) {
_size = 0;
_capacity = capacity;
}
int get(int key) {
//在map中查找是否存在key
auto ret = _umap.find(key);
if(ret == _umap.end()) //找不到
return -1;
LIST_ITER it= _umap[key];
//将此节点移到list尾部
_lst.splice(_lst.end(), _lst, it);
return it->second;
}
void put(int key, int value) {
//map中是否存在key
auto ret = _umap.find(key);
if(ret == _umap.end())
{
//map中没有key值
if(_size >= _capacity)
{
//map表中删除头节点的相关信息
_umap.erase(_lst.begin()->first);
//list中头删
_lst.pop_front();
--_size;
}
//list尾插
_lst.push_back(make_pair(key,value));
//map表中插入
_umap[key] = --(_lst.end());
++_size;
}
else
{
//map中存在key值,修改value值
LIST_ITER it = _umap[key];
it->second = value;
//将此节点移到list尾部
_lst.splice(_lst.end(), _lst, it);
}
}
private:
unordered_map<int, LIST_ITER> _umap;
list<pair<int, int>> _lst;
int _capacity;
int _size;
};