转自:https://www.cnblogs.com/cpselvis/p/6272096.html
LRU缓存
像浏览器的缓存策略、memcached的缓存策略都是使用LRU这个算法,LRU算法会将近期最不会访问的数据淘汰掉。LRU如此流行的原因是实现比较简单,而且对于实际问题也很实用,良好的运行时性能,命中率较高。下面谈谈如何实现LRU缓存:
新数据插入到链表头部
每当缓存命中(即缓存数据被访问),则将数据移到链表头部
当链表满的时候,将链表尾部的数据丢弃
LRU Cache具备的操作:
set(key,value):如果key在hashmap中存在,则先重置对应的value值,然后获取对应的节点cur,将cur节点从链表删除,并移动到链表的头部;若果key在hashmap不存在,则新建一个节点,并将节点放到链表的头部。当Cache存满的时候,将链表最后一个节点删除即可。
get(key):如果key在hashmap中存在,则把对应的节点放到链表头部,并返回对应的value值;如果不存在,则返回-1。
C++实现:
LRU实现采用双向链表 + hashMap 来进行实现。这里采用双向链表的原因是:如果采用普通的单链表,则删除节点的时候需要从表头开始遍历查找,效率为O(n),采用双向链表可以直接改变节点的前驱的指针指向进行删除达到O(1)的效率。使用hashMap来保存节点的key、value值便于能在O(1)的时间查找元素,对应get操作。
#include <cstdio>
#include <cstring>
#include <map>
#include <iostream>
using namespace std;
struct cacheNode
{
int key;
int val;
cacheNode *pre,*next;
cacheNode(int k, int v):key(k),val(v),pre(nullptr),next(nullptr){}
};
class LRUCache {
private:
int size; //Cache size
cacheNode *head,*tail;
map<int,cacheNode*>mp; //hashmap
public:
LRUCache(int capacity) { //构造函数
size = capacity;
head = nullptr;
tail = nullptr;
}
int get(int key) { //访问key
map<int,cacheNode*>::iterator it = mp.find(key);
if (it != mp.end()) { //访问命中,将数据移动到链表头部
cacheNode* node = it->second;
remove(node);
setHead(node);
return node->val;
}
else
return -1; //访问失败
}
void set(int key,int value) { //访问key,如果访问命中,则重置val的值,对访问失败的时候,
//新建一个节点插到表头且当容量满的时候先删除最后一个节点再插入
map<int,cacheNode*>::iterator it = mp.find(key);
if (it != mp.end()) {
cacheNode* node = it->second;
node->val = value;
remove(node);
setHead(node);
}
else {
cacheNode* newNode = new cacheNode(key,value);
if (mp.size() >= size) {
map<int,cacheNode*>::iterator iter = mp.find(tail->key);
remove(tail);
mp.erase(iter);
}
setHead(newNode);
mp[key] = newNode;
}
}
void remove(cacheNode* node) { //双向链表
if (node->pre != nullptr) { //如果不是头结点
node->pre->next = node->next;
}
else {
head = node->next; //是头结点则头指针指向node的下一个节点
}
if (node->next != nullptr) {//不是尾节点
node->next->pre = node->pre;
}
else {
tail = node->pre; //是尾节点则尾指针指向node的前一个节点
}
delete node; //释放内存
}
void setHead(cacheNode* node) {
node->next = head;
node->pre = nullptr;
if (head != nullptr) {
head->pre = node;
}
head = node;
if (tail == nullptr) {
tail = head;
}
}
};
int main()
{
LRUCache* lruCache = new LRUCache(2);
lruCache->set(2,1);
lruCache->set(1,1);
cout << lruCache->get(2) << endl;
lruCache->set(4,1);
cout << lruCache->get(1) << endl;
cout << lruCache->get(2) << endl;
}