LRU的实现
运用你所掌握的数据结构,设计和实现一个LRU (最近最少使用) 缓存机制 。它应该支持以下操作: 获取数据 get
和 写入数据 put
。
获取数据 get(key)
- 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value)
- 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
思路:
LRU实现采用双向链表 + hash_map 来进行实现。这里采用双向链表的原因是:如果采用普通的单链表,则删除节点的时候需要从表头开始遍历查找,效率为O(n),采用双向链表可以直接改变节点的前驱的指针指向进行删除达到O(1)的效率。使用map来保存节点的key、value值便于能在O(logN)的时间查找元素,对应get操作。
代码:
#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
#include<iostream>
#include<hash_map>
#include<algorithm>
using namespace std;
struct CacheNode {
int key;
int value;
CacheNode *pre;
CacheNode *next;
CacheNode(int k, int v) :key(k), value(v), pre(nullptr), next(nullptr) {}
};
class LRUCache {
public:
LRUCache(int capacity) :size(capacity), head(nullptr), tail(nullptr) {}
int get(int key);
void set(int key,int value);
void remove(CacheNode *node);
void SetHead(CacheNode *node);
CacheNode *GetHead();
private:
int size;//最大缓存数
CacheNode *head, *tail;
hash_map<int, CacheNode *>map;//int是关键字
};
int LRUCache::get(int key)
{
auto it = map.find(key);//先在hash表中查一下是否有该关键字
//存在该关键字
if (it != map.end())
{
CacheNode *node = it->second;
//要获取的关键字正好位于双向链表的头节点
if (node == GetHead())
return node->value;
else
{
remove(node);
SetHead(node);
}
return node->value;
}
else
return -1;
}
void LRUCache::set(int key, int value)
{
auto it = map.find(key);//先在hash表中查一下是否有该关键字
//以前已经存在该关键字,需要修改值
if (it != map.end())
{
CacheNode *node = it->second;
//要获取的关键字正好位于双向链表的头节点
if (node =