概述
题目思路:模拟LRU缓存的原理。
需要实现的内容:实现一个LRUcache类,其中包括两个方法,get方法相当于调取元素,经过get后的元素要更新位置到最前面;put方法为放入新元素,如果之前缓存没有这个元素,则新建元素并放入(如果放入之前缓存已满,就要淘汰最近最久没用的元素,即最后面的元素),如果之前缓存中就有,那就相当于执行get方法。
实现的方法:利用双向链表和哈希表。其中双向链表的头尾均设置哑节点,便于操作:
(借一张图)
双向链表结点的定义:
//双向链表节点
struct DlinkedNode {
int key, value;
DlinkedNode* prev;
DlinkedNode* next;
//构造函数
DlinkedNode() : key(0), value(0), prev(nullptr), next(nullptr) {} //默认初始化
DlinkedNode(int _key, int _value) : key(_key), value(_value), prev(nullptr), next(nullptr) {}
};
哈希表:
unordered_map<int, DlinkedNode*> cache;
原理:当get或put元素时,提供的是key,需要从哈希表中根据key获得对应的链表结点;而当移除元素时,也需要根据key来更新哈希表(cache.erase)
get和put方法的实现:根据它们的功能,可以分解成:将元素添加至缓存的头部、移除链表中的某个元素,根据这两个方法又可以实现:将元素移动至缓存头部、淘汰表尾元素。
完整代码如下:
//双向链表节点
struct DlinkedNode {
int key, value;
DlinkedNode* prev;
DlinkedNode* next;
//构造函数
DlinkedNode() : key(0), value(0), prev(nullptr), next(nullptr) {} //默认初始化
DlinkedNode(int _key, int _value) : key(_key), value(_value), prev(nullptr), next(nullptr) {}
};
class LRUCache {
private:
//创建哈希表
unordered_map<int, DlinkedNode*> cache;
//哑节点的表头尾
DlinkedNode* dummyHead;
DlinkedNode* dummyTail;
int size; //缓存中元素的数量
int capacity; //缓存容量
public:
LRUCache(int _capacity): capacity(_capacity), size(0) { //构造函数
//哑节点的表头尾,也可称为哨兵结点
dummyHead = new DlinkedNode();
dummyTail = new DlinkedNode();
//初始时双向链表只有这两个节点
dummyHead->next = dummyTail;
dummyTail->next = dummyHead;
}
//以下为实现get和put所必要的一些函数:addToHead,removeNode,moveToHead,removeTail
//将元素 添加 至缓存的头部
void addToHead(DlinkedNode* node) {
//新元素的next,prev指针
node->prev = dummyHead;
node->next = dummyHead->next;
dummyHead->next->prev = node; //新元素原来位置的结点的prev更新为新元素
dummyHead->next = node; //哑节点表头的next更新为新元素
}
//移除节点
void removeNode(DlinkedNode* node) {
node->next->prev = node->prev;
node->prev->next = node->next;
}
//元素移动到头部:先移除,再添加
void moveToHead(DlinkedNode* node) {
removeNode(node);
addToHead(node);
}
//淘汰表尾元素
DlinkedNode* removeTail() {
DlinkedNode* tail = dummyTail->prev;
removeNode(tail);
return tail;
}
//从缓存中获取元素:先通过哈希表根据key找到节点位置,再把它移动至头部
int get(int key) {
if(!cache.count(key))
return -1;
//如果存在
DlinkedNode* node = cache[key];
moveToHead(node);
return node->value;
}
//向缓存中插入元素
void put(int key, int value) {
//如果缓存中没有这一元素,就真的插入
if(!cache.count(key)) {
DlinkedNode* node = new DlinkedNode(key, value); //新建节点
cache[key] = node; //更新哈希表
addToHead(node); //放入缓存,因为是新元素,所以要加入到头部
++size;
//如果缓存满了
if(size > capacity) {
DlinkedNode* tail = removeTail(); //淘汰尾部
cache.erase(tail->key); //更新哈希表
delete tail;
--size;
}
}
//如果cache中已有该元素,则与get操作类似
else {
DlinkedNode* node = cache[key];
node->value = value; //更新cache
moveToHead(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);
*/
最后
以上就是可耐向日葵为你收集整理的[LeetCode] 146.LRU缓存的全部内容,希望文章能够帮你解决[LeetCode] 146.LRU缓存所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复