LRU
LRU(Least Recently Used),即最近最少使用
它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
如果对题目还未理解清楚的,可以去https://mp.weixin.qq.com/s/mxCtce_PtNzYzUb80TDpKg观看动画演示。
思路:
首先,需要想清楚到底用哪个数据结构用来进行存储,因为每次get和put时,都会把响应的键值对移位置(以便实现最近最少使用的删除),也就是多数情况下要在此容器的中间位置进行删除操作,所以应该选择链式存储结构,对应STL的list.因为无论是选择序列容器的vector还是deque在中间位置进行插入移除操作,都要耗费线性时间。其次,保存键值对可以用pair<>来封装一个int型的键和一个int型的value。即需要维护一个list<pair<int,int>>类型的容器。然后,如何实现将最近最少使用的键值对从缓存中清除掉呢?
其实很简单,我们可以用一个队列来实现,(这里按照队尾入队,队头出队的原则),每次使用这个键值对的时候(即进行get或put方法)将此键值对放入队尾,如果此时容量不够了,又进行了put操作,那么队头元素出队即可。
如果看过我之前的文章,很容易想起什么数据结构最适合在这使用,对,没错,就是链式队列
时间复杂度
在进行get和put方法时,毫无疑问需要遍历此链式队列,如果我们进行遍历,那么时间复杂度为O(n),如果调用STL库中的删除和查找算法的话,那么时间复杂度为O(1),(库中的复杂度我们不计算!)
好了,不多说,上代码!
LRU实现:
#pragma once
#include <list>
#include<utility>
#include <algorithm>
using namespace std;
class LRUCache
{
/**
* 链栈的C++实现
* @author wzx
* @data 2019年3月4日
*/
private:
list<pair<int,int>> m_list; //存放键值对的链式队列
int m_Capacity; //缓存器链表m_list的容量
public:
LRUCache(int Capacity);
LRUCache() {};
~LRUCache() = default;
void put(int key, int value);
int get(int key);
};
LRUCache::LRUCache(int Capacity):m_Capacity(Capacity)
{}
void LRUCache::put(int key, int value)
{
m_list.remove_if([=](pair<int, int>p) {return p.first == key; });
if (m_list.size() < m_Capacity)
{
m_list.emplace_back(make_pair(key, value));
}
else
{
m_list.pop_front();
m_list.emplace_back(make_pair(key, value));
}
}
int LRUCache::get(int key)
{
list<pair<int,int>>::iterator ite = find_if(m_list.begin(), m_list.end(),
[=](pair<int, int> mpair) {return mpair.first == key; });
if (ite != m_list.end())
{
int value= (*ite).second;
m_list.remove(make_pair(key, value));
m_list.emplace_back(make_pair(key, value));
return value;
}
else
{
return -1;
}
}
代码总结:
严格意义上讲,实现代码的时间复杂度O(n),因为调用库的算法的时间复杂度为O(n)。此外还可以将list中的地址与key映射,然后存储到一个关联容器中,因为关联容器的底层数据结构是红黑树,时间复杂度为O(log(2)N),这种实现如果有时间的话可以实现出来然后再上传。
另外,感谢大锤提示我进行下一步的思考,即在get的时候可不可以先不放在队尾,而等用户进行了N次get后再放入队尾,这样不至于频繁操作,将用户经常获取的键值对进行优化操作。抽空再实现。