LRU:最久未使用置换原则
均以3个内存块举例。
FIFO:先进先出
LRU算法代码实现:
/*
双链表:最底端是最久未使用的
哈希表:通过缓存数据的键映射到其在双向链表中位置
对hash表做put和get:
给LRU的cache用map
初始化
get(LRU核心):获取链表中该页号存的值,如果不存在,则返回-1,如果存在,则把它移动到链表顶部,因为算使用一次
put:(LRU核心):只要是put过的,都要移动到头顶,且分为当前节点是否已经存在,不存在则创建新节点加入到头部,如果链表过长,则删除尾
借助map:根据页号寻找链表节点
借助DLinkNode:把当前内存块串联起来
*/
class DLinkNode
{
public:
int key, val;
DLinkNode* pre;
DLinkNode* nxt;
DLinkNode(): key(0), val(0), pre(nullptr), nxt(nullptr){}
DLinkNode(int _key, int _val):key(_key), val(_val), pre(nullptr), nxt(nullptr){}
};
class LRUCache {
// 根据存入数据,找对应链表
unordered_map<int, DLinkNode*> cache;
DLinkNode* head;
DLinkNode* tail;
// 缓存块数量和当前大小
int size;
int capacity;
public: // 内(参)
LRUCache(int capacity):capacity(capacity), size(0)
{
head = new DLinkNode();
tail = new DLinkNode();
head->nxt = tail;
tail->pre = head;
}
// 存:获取当前页面的值,如果存在就获取且让它到链表顶部
int get(int key)
{
// 页面号不存在则返回-1
if (cache.find(key) == cache.end())
return -1;
// key存在,先哈希定位,再移动到头
DLinkNode* node = cache[key];
moveToHead(node);
return node->val;
}
// 找值,且移动到首位
void put(int key, int val)
{
// 不存在该key,则创建新节点
if (cache.find(key) == cache.end())
{
DLinkNode* node = new DLinkNode(key, val);
cache[key] = node;
// 单独的节点加到头部
addToHead(node);
++size;
// 容量超了,就删除尾部
if (size > capacity)
{
DLinkNode* tail = removeTail();
cache.erase(tail->key);
delete tail;
--size;
}
}
// 存在则获取
else
{
// 如果key存在,map中获取该节点,移动到头
DLinkNode* node = cache[key];
// 不必做判断也可
if (node->val != val)
node->val = val;
moveToHead(node);
}
}
// 已存在与链表中的节点移动到头部,利用删除和插入顶部两个函数
void moveToHead(DLinkNode* node)
{
// 两个顺序无所谓
removeNode(node);
// 新节点,放到头部
addToHead(node);
}
// 删除链表节点
void removeNode(DLinkNode* node)
{
// 当前节点的左右两链表节点链接做改变
node->pre->nxt = node->nxt;
node->nxt->pre = node->pre;
}
// 把一个节点,放到头部:不论是否已在链表中
void addToHead(DLinkNode* node)
{
// 动头和当前
node->nxt = head->nxt;
node->pre = head;
head->nxt->pre = node;
head->nxt = node;
}
// 删除链表尾部
DLinkNode* removeTail()
{
DLinkNode* node = tail->pre;
removeNode(node);
return node;
}
};
/**
* 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);
*/