实现LRU
LRU(Least Recently Used),即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰,常用于缓存机制。
实现LRU需要一个Map和一个双向链表。
我们规定,head->next 为最久未使用节点,head->prev为最新节点,每次当访问或修改已有节点时,将其移动到尾部,这样就可以保证其相对次序。
map的value保存链表节点的指针,保证O(1) 时间定位节点。
当缓存未满时,直接向map插入新项,链表尾插新节点。
当缓存已满,删除头结点,尾插新节点。
get时,需要刷新其相对次序,将其旧位置断链,重新尾插。
时间复杂度均为O(1)。
struct my_ListNode
{
int _key;
int _data;
my_ListNode* _prev;
my_ListNode* _next;
my_ListNode(int key, int val) :
_key(key),
_data(val),
_prev(nullptr),
_next(nullptr) {}
};
class my_list
{
typedef my_ListNode Node;
public:
my_list() :
_head(new Node(int(), int()))
{
_head->_prev = _head;
_head->_next = _head;
}
~my_list()
{
if (!empty())
{
Node* cur = _head->_next;
while (cur != _head)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
}
delete _head;
}
bool empty()
{
return _head->_prev == _head && _head->_next == _head;
}
size_t size()
{
if (empty())
return 0;
size_t count = 0;
Node* cur = _head->_next;
while (cur != _head)
{
cur = cur->_next;
count++;
}
return count;
}
//尾插
void push_back(Node* newNode)
{
Node* tail = _head->_prev;
newNode->_prev = tail;
tail->_next = newNode;
newNode->_next = _head;
_head->_prev = newNode;
}
//返回key
int pop_back()
{
if (empty())
return -1;
Node* tail = _head->_prev;
int key = tail->_key;
Node* newTail = tail->_prev;
newTail->_next = _head;
_head->_prev = newTail;
//delete tail;
return key;
}
//返回key
int pop_front()
{
if (empty())
return -1;
Node* del = _head->_next;
int key = del->_key;
Node* next = del->_next;
_head->_next = next;
next->_prev = _head;
delete del;
return key;
}
void erase(Node* pos)
{
if (empty())
return;
Node* prev = pos->_prev;
Node* rear = pos->_next;
prev->_next = rear;
rear->_prev = prev;
}
private:
Node* _head;
};
class LRUCache {
typedef my_ListNode Node;
public:
LRUCache(int capacity) :
_capacity(capacity) {}
int get(int key) {
//找不到返回-1
if (_mp.find(key) == _mp.end())
return -1;
Node* addr = _mp[key];
int ret = addr->_data;
//更新次序
_li.erase(addr);
_li.push_back(addr);
return ret;
}
void put(int key, int value) {
if (_mp.size() == _capacity && _mp.find(key) == _mp.end())
{
//先删除最近最少使用
int del = _li.pop_front();
_mp.erase(del);
}
if (_mp.find(key) != _mp.end())
{
Node* node = _mp[key];
node->_data = value;
_li.erase(node);
_li.push_back(node);
}
else
{
Node* newNode = new Node(key, value);
_mp.insert(pair<int, Node*>(key, newNode));
_li.push_back(newNode);
}
}
private:
const int _capacity;
map<int, Node*> _mp;
my_list _li;
};
int main()
{
LRUCache* cache = new LRUCache(2);
cache->put(2, 1);
cache->put(2, 2);
cout << cache->get(2) << endl; // 返回 1
cache->put(1, 1);
cache->put(4, 1);
cout << cache->get(2) << endl; ; // 返回 -1 (未找到)
}