LeetCode --- LRU Cache
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get
and set
.
get(key)
- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value)
- Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
题目要求:设计一个最近最久未使用缓存,实现其get和set方法。
LRU算法由于在自己工作的项目中没有使用过,所以也不太熟悉。自己思考了一下,关键点有下面几个:
(1)找一个合适的数据结构来存这些(key,value)
(2)每当遍历过该结点,便将该节点置于最前面。
下面给出自己做的(TimeLimited)两种,第一种使用Queue,第二种使用Vector。
只使用Queue,代价是遍历到该结点,然后移动其他结点,时间浪费很大。
只使用Vector,代价和Queue基本上差不多,遍历和移动都很耗时。
如果这个是放在实时的系统中,数据量小还能承受,数据量大的话,遍历一次都要很费时间。
//只使用队列
struct Item
{
int key;
int value;
};
class LRUCache{
public:
LRUCache(int capacity) {
m_icapacity = capacity;
}
int get(int key) {
if (qItems.size() <= 0)
{
return -1;
}
for (int i = 0; i < qItems.size(); i++)
{
Item temp = qItems.front();
if (temp.key == key)
{
for (int j = i; j < qItems.size(); j++)
{
Item temp1 = qItems.front();
qItems.pop();
qItems.push(temp1);
}
return temp.value;
}
else
{
qItems.pop();
qItems.push(temp);
}
}
return -1;
}
void set(int key, int value) {
if (get(key) == -1)
{
Item temp;
temp.key = key;
temp.value = value;
if (qItems.size() > m_icapacity)
{
qItems.pop();
qItems.push(temp);
}
else
{
qItems.push(temp);
}
}
}
private:
queue<Item>qItems;
int m_icapacity;
};
//只使用Vector
struct Item
{
int key;
int value;
};
class LRUCache{
public:
LRUCache(int capacity) {
m_icapacity = capacity;
index = -1;
}
int get(int key) {
if (qItems.size() <= 0)
{
return -1;
}
for (int i = 0; i < qItems.size(); i++)
{
Item temp = qItems[i];
if (temp.key == key)
{
if (i != (qItems.size()-1))
{
Item change = qItems[i];
for (int j = i; i < qItems.size() - 1; i++)
{
qItems[j] = qItems[j+1];
}
qItems[qItems.size()-1] = change;
index = qItems.size()-1;
}
else
{
index = i;
}
return temp.value;
}
}
return -1;
}
void set(int key, int value) {
int getval = get(key);
if (getval == -1)
{
Item temp;
temp.key = key;
temp.value = value;
if (qItems.size() >= m_icapacity)
{
bool isused = false;
vector<Item>::iterator it = qItems.begin();
qItems.erase(it);
qItems.push_back(temp);
}
else
{
qItems.push_back(temp);
}
}
else
{
if (getval != value)
{
if (index != -1)
{
qItems[index].value = value;
index = -1;
}
}
}
}
private:
vector<Item>qItems;
int m_icapacity;
int index;
};
然后自己想不出来了,于是求助度娘,找了一下。为了满足效率,一般使用两个结构来存储响应的元素。使用List,满足插入和删除的效率;使用Map,满足遍历的效率。
每次遍历Map中的Key,相应的将该元素调整到List的头结点,然后将该结点存入到Map中对应的位置。如果超过数量限制,则删除List中最后一个结点,同时删除Map中对应的元素。
自己STL用的还不是很熟悉:
listItems.splice(listItems.begin(), listItems, tempit);这个函数可以将一个元素调整到队列的头。
struct Item
{
int key;
int value;
};
class LRUCache{
public:
LRUCache(int capacity) {
m_icapacity = capacity;
}
int get(int key)
{
map<int, list<Item>::iterator>::iterator pfind = mapItems.find(key);
if (pfind != mapItems.end())
{
list<Item>::iterator tempit = pfind->second;
listItems.splice(listItems.begin(), listItems, tempit);
pfind->second = listItems.begin();
return listItems.begin()->value;
}
return -1;
}
void set(int key, int value)
{
map<int, list<Item>::iterator>::iterator pfind = mapItems.find(key);
if (pfind == mapItems.end())
{
if (mapItems.size() == m_icapacity)
{
Item tempItem = listItems.back();
mapItems.erase(tempItem.key);
listItems.pop_back();
tempItem.key = key;
tempItem.value = value;
listItems.push_front(tempItem);
mapItems[key] = listItems.begin();
}
else
{
Item tempItem;
tempItem.key = key;
tempItem.value = value;
listItems.push_front(tempItem);
mapItems[key] = listItems.begin();
}
}
else
{
list<Item>::iterator tempit = pfind->second;
if(tempit->value != value)
{
tempit->value = value;
}
listItems.splice(listItems.begin(), listItems, tempit);
pfind->second = listItems.begin();
}
}
private:
map<int , list<Item>::iterator > mapItems;
list<Item>listItems;
int m_icapacity;
};