LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。
为了可以在 O(1) 时间复杂度内完成get()和put()两种操作,我们使用两个STL容器:
unordered_map<int,list<pair<int,int>>::iterator> m;
无序map,存储已经存在的键值对,保证查找时间复杂度为O(1),注意第二个元素保存的是list的迭代器
list<pair<int,int>> cache;
一个链表,来保存键值对的使用时间顺序
原题如下:
Leetcode146. LRU缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
下面就直接贴上源码吧,里边我标注的很详细:
class LRUCache {
public:
LRUCache(int capacity) {
cap=capacity;
}
int get(int key) {
//如果cache中不存在此键值,返回-1;
if(m.count(key)==0) return -1;
else
{
auto iter=m[key];//指向该键值对的迭代器
//将该键值对放到list的前面
cache.splice(cache.begin(),cache,iter);
//返回该键值对的值
return cache.begin()->second;
}
}
void put(int key, int value) {
//如果list中不存在该键值
if(m.count(key)==0)
{
//若list已经满了,先删除
if(cache.size()==cap)
{
m.erase(cache.back().first);
cache.pop_back();
}
//直接添加要放入的键值对
cache.push_front(make_pair(key,value));
m[key]=cache.begin();
}
//如果list中存在该键值,直接修改值,并且将其放入list前面
else
{
auto iter=m[key];
iter->second=value;
cache.splice(cache.begin(),cache,iter);
m[key]=cache.begin();
}
}
unordered_map<int,list<pair<int,int>>::iterator> m;//无序map,存储已经存在的键值对,保证查找时间复杂度为O(1)
list<pair<int,int>> cache;//需要一个链表,来保存键值对的使用时间顺序
int cap=0;//确定目前存在链表队列中的键值对数量
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/