LRU最近最少使用 剔出缓存序列
题目::
样例:
保姆式代码解析 C++
//对于操作(新节点插入、已有节点value更新、已有节点取value)都会将key节点的状态置为最近一次的操作
//因为cache_size是有限的,存在操作插入节点时cache满了,需要LRU
//以上两个过程的分析,就需要我们能对一种数据结构的头尾都能操作
//采用双向链表,链表节点结构体
struct Node{
int key;
int value;
Node* pre;
Node* next;
//头尾节点
Node() {
key = 0;
value = 0;
prev = nullptr;
next = nullptr;
}
//值节点
Node(int _key, int _value){
key = _key;
value = _value;
prev = nullptr;
next = nullptr;
}
};
//节点的维护,我们已经想到使用双向链表,针对此题的小操作(取值,改值)并且这些操作都是针对唯一的key值进行的。
//我们采用哈希表来存储key值和key值对应的节点。
//声明头尾节点,方便链表头尾元素的操作。
class LRUCache {
private:
unordered_map<int, DLinkedNode*> cache;
Node* head;
Node* tail;
int size;//记录现在链表中的容量
int capacity;//输入所给的容量
public:
LRUCache(int _capacity){ //初始化
capacity = _capacity;
head = new Node();
tail = new Node();
head->next = tail;
tail->prev = head;
size = 0;
}
int get(int key) {
if (!cache.count(key)) {
return -1;
}
// 如果 key 存在,先通过哈希表定位,再移到头部
Node* node = cache[key];
moveToHead(node);
return node->value;
}
void put(int key, int value){
if (!cache.count(key)) {
// 如果 key 不存在,创建一个新的节点
Node* node = new Node(key, value);
// 添加进哈希表
cache[key] = node;
// 添加至双向链表的头部
addToHead(node);
++size;
if (size > capacity) {
// 如果超出容量,删除双向链表的尾部节点
Node* removed = removeTail();
// 删除哈希表中对应的项
cache.erase(removed->key);
// 防止内存泄漏
delete removed;
--size;
}
}
else {
// 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
Node* node = cache[key];
node->value = value;
moveToHead(node);
}
}
//双向链表的一些节点操作,理解默写就完了。
void removeNode(Node* node){//断开一个节点
node->pre->next = node->next;
node->next->pre = node->pre;
}
void addToHead(Node* node){//在头部插入一个节点。
node->next = head->next;
node->pre = head;
head->next->pre = node;
head->next = node;
}
void moveToHead(Node* node){//把一个节点放到头结点。
removeNode(node);
addToHead(node);
}
Node* removeTail(){ 删除一个节点。在外部使用delete
Node* node = tail->pre;
removeNode(node);
return node;
}
};
使用hash map 确实更够提高唯一key时,对查找key的操作(cache.count(key))。如果只建立双向链表,在确定key是否存在时需要遍历整个链表