什么是LRU
LRU是什么?按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非常著名的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!
怎么实现
这个题的设计思路就是哈希表加双向链表(需要定制,从尾部加,从头部出)
为什么需要哈希表呢?
假设我们需要存储(A,3)这样一个数据,这里哈希表中存储的key为对应的A,而value则是这样一个节点的内存地址。这样,我们在修改的时候可以通过哈希表直接修改双向链表中的内容,并且当我们需要进行优先级的调整的时候可以以常数时间复杂度找到对应节点而不需要遍历行为。
框图如下
示例代码
#include <iostream>
#include <unordered_map>
using namespace std;
class Node
{
public:
Node(int value)
:m_value(value)
, next(nullptr)
, last(nullptr)
{
}
public:
int m_value;
Node *next;
Node *last;
};
class NodeDoubleLinkedList
{
public:
NodeDoubleLinkedList()
:head(nullptr)
, tail(nullptr)
{
}
// 增加一个节点
void addNode(Node &newNode)
{
if (head == nullptr)
{
head = &newNode;
tail = &newNode;
}
else
{
tail->next = &newNode;
newNode.last = tail;
tail = tail->next;
}
}
// 将节点移动到队列尾,也就是提升其优先级为最高
void moveNodeToTail(Node &node)
{
if (&node == tail)
{
return;
}
if (&node == head)
{
head = head->next;
head->last = nullptr;
}
else
{
node.last->next = node.next;
node.next->last = node.last;
}
tail->next = &node;
node.last = tail;
node.next = nullptr;
tail = tail->next;
}
// 删除队列头
Node *removeHead()
{
if (head == nullptr)
{
//抛出异常
//return nullptr;
}
Node *res = head;
if (this->head == this->tail)
{
this->head = nullptr;
this->tail = nullptr;
}
else
{
head = res->next;
head->last = nullptr;
res->next = nullptr;
}
return res;
}
public:
Node *head; // 优先级低
Node *tail; // 优先级高
};
class MyCache
{
public:
MyCache(int capacity)
{
if (capacity < 1)
{
throw exception("capacity error");
}
this->capacity = capacity;
}
// 由key查询对应的value
int get(int key)
{
if (keyNodeMap.find(key) == keyNodeMap.end())
{
throw exception("key not exist");
}
Node *res = keyNodeMap[key];
nodeList.moveNodeToTail(*res);
return res->m_value;
}
// 加入键值对
void set(int key, int value)
{
if (keyNodeMap.find(key) != keyNodeMap.end())
{
Node * node = keyNodeMap[key];
node->m_value = value;
this->nodeList.moveNodeToTail(*node);
}
else
{
Node *newNode = new Node(value);
this->keyNodeMap[key] = newNode;
this->nodeKeyMap[newNode] = key;
this->nodeList.addNode(*newNode);
if (this->keyNodeMap.size() == this->capacity + 1)
{
this->removeMostUnusedCache();
}
}
}
// 删除优先级最低的数据
void removeMostUnusedCache()
{
Node *removeNode = this->nodeList.removeHead();
int removeKey = this->nodeKeyMap[removeNode];
this->nodeKeyMap.erase(removeNode);
this->keyNodeMap.erase(removeKey);
}
private:
unordered_map<int, Node*> keyNodeMap;
unordered_map<Node*, int> nodeKeyMap; //
int capacity; // 模拟内存大小
NodeDoubleLinkedList nodeList; // 优先级队列,越靠近tail,优先级越高
};
int main(int argc, char ** argv)
{
MyCache testCache(3);
testCache.set(1,2);
testCache.set(2,3);
testCache.set(3,4);
testCache.get(1);
system("pause");
return EXIT_SUCCESS;
}