思路:
这里等于是构建一个双向链表,链表的值的部分是一个哈希表,他的作用是可以使用哈希表很快的找到链表的指定节点。
(1)构建链表
class DLinkNode {
public:
int key, value;
DLinkNode* prev, * next;
DLinkNode() : key(0), value(0), prev(nullptr), next(nullptr) {}
DLinkNode(int _key, int _value) : key(_key), value(_value), prev(nullptr), next(nullptr) {}
};
(2)初始化参数
用capacity去保存容量,size去控制每次加入后的容量。head和tail是用来控制链表的头尾,head始终指向头,tail始终指向末尾。
int size, capacity;
DLinkNode* head, * tail;
unordered_map<int, DLinkNode*> hash;
(3)初始化链表
LRUCache(int capacity) :
size(0), capacity(capacity)
{
// 初始化双向链表
head = new DLinkNode();
tail = new DLinkNode();
head->next = tail;
tail->prev = head;
}
(4)两个操作
第一个操作是get一个key,返回它的值。第二个操作是put,修改对应key的值,如果不存在就new一个,如果超过上限就去掉第一个(使用率最低的)。所以我们对链表有以下操作
①删除某个位置的节点。 void deleteNode(int key)
②末尾添加一个节点。 void add2Tail(int key)
③超过上限的时候,删除第一个节点。void deleteHead()
操作的时候,先理清楚逻辑:
get():判断是否已经有这个值,如果有这个值,就返回对应的value,并且将这个节点移动到最后。
int get(int key) {
// 若不存在 key
if (hash.count(key) == 0) {
return -1;
}
move2Tail(key); // 最近访问的 key 挪到链尾
return hash[key]->value;
}
put():如果存在key就修改值,同时移动,这里和put差不多。如果不存在就new一个新节点,并且插入链尾,size++,如果size超过了capacity就删除链头节点。
void put(int key, int value) {
// 若已存在 key
if (hash.count(key) != 0) {
// 修改已有 key 所对应的 value
hash[key]->value = value;
move2Tail(key); // 挪到链尾
return;
}
// 若不存在则 new
DLinkNode* newNode = new DLinkNode(key, value);
hash[key] = newNode;
// 插入链尾
add2Tail(key);
size++;
// 若超出规定容量
if (size > capacity) {
deleteHead();
size--;
}
}
(5)对链表进行操作
void deleteNode(int key) {
// key 的前驱 next 指向 key 的后继
hash[key]->prev->next = hash[key]->next;
// key 的后继 prev 指向 key 的前驱
hash[key]->next->prev = hash[key]->prev;
}
void add2Tail(int key) {
// tail 的前驱 next 指向 key
tail->prev->next = hash[key];
// key 的 prev 指向 tail 的前驱
hash[key]->prev = tail->prev;
// tail 的 prev 指向 key
tail->prev = hash[key];
// key 的 next 指向 tail
hash[key]->next = tail;
}
void move2Tail(int key) {
deleteNode(key);
add2Tail(key);
}
void deleteHead() {
DLinkNode* deleted = head->next;
// head 的 next 指向 head 的后继 next
head->next = deleted->next;
// head 后继的 prev 指向 head
deleted->next->prev = head;
// 同时也从 hash 中注销
hash.erase(deleted->key);
delete deleted;
}