分析
实现一个最近最少使用的数据结构.同时要求get和put都是常数复杂程度.首先我们先来考虑如何在O(1)时间内获取.显而易见,要想在O(1)时间内获取对应的数据,我们需要用的哈希表,哈希表可以O(1)时间内获取对应key值的val.再然后就是考虑如何判断出最近最少.这个我们使用双链表来维护.每当我们对一个数进行操作之后,就将它添加到链表的头部,这样链表的尾部就是最近最少使用的节点.
code & 注释
class LRUCache {
public:
// 创建双链表节点
struct Node{
// k-v键值对
int key, val;
// 左右指针
Node *left, *right;
// 初始化方法
Node(int _key, int _val) : key(_key), val(_val), left(NULL), right(NULL){}
}*L, *R; // 头尾节点
// 容量
int n;
// 哈希表
unordered_map hash;
// 删除一个节点
void remove(Node* p) {
// 让当先节点的前一个节点指向当前节点的下一个节点
p->left->right = p->right;
// 让当前节点的后一个节点只想当前节点的前一个节点
p->right->left = p->left;
}
// 在头部添加一个节点
void insert(Node* p) {
// 当前节点分别指向虚拟头和第一个节点
p->left = L;
p->right = L->right;
// 下两句顺序不能变,如果变化,就无法访问到原来的第一个节点
// 让与原来的第一个节点指向当前节点
L->right->left = p;
// 让虚拟头指向当前节点
L->right = p;
}
LRUCache(int capacity) {
// 初始化容量
n = capacity;
// 创建虚拟头尾节点
L = new Node(1, 1), R = new Node(1, 1);
// 初始化双链表
L->right = R;
R->left = L;
}
int get(int key) {
// 如果当前key不存在直接返回即可
if (hash.count(key) == 0) return -1;
// 存在的话,直接获取
auto p = hash[key];
// 从链表中原来的位置删除,添加到虚拟头节点后面
remove(p);
insert(p);
// 返回值
return p->val;
}
void put(int key, int value) {
// 如果当前key不存在,需要新建
if (hash.count(key) == 0) {
// 如果已经达到了容量
if (hash.size() == n) {
// 删除虚拟尾节点的前一个节点
auto p = R->left;
remove(p);
// 同时在哈希表中删除
hash.erase(p->key);
delete p;
}
// 创建新节点
auto p = new Node(key, value);
// 更新哈希表
hash[key] = p;
// 插入双链表头部
insert(p);
} else {
// 如果当前key存在,只用更新value即可
auto p = hash[key];
// 更新节点的值
p->val = value;
// 从原来的位置删除,添加到双链表头部
remove(p);
insert(p);
}
}
};



