LRU缓存
- 题目描述
- 示例
- 解题思路
- C++ 代码
题目描述
请你设计并实现一个满足 LRU (最近最久未使用) 缓存 约束的数据结构。
 实现 LRUCache 类:
- LRUCache(int capacity)以 正整数 作为容量- capacity初始化- LRU缓存
- int get(int key)如果关键字- key存在于缓存中,则返回关键字的值,否则返回- -1。
- void put(int key, int value)如果关键字- key已经存在,则变更其数据值- value;如果不存在,则向缓存中插入该组- key-value。如果插入操作导致关键字数量超过- capacity,则应该 逐出 最久未使用的关键字。
 函数- get和- put必须以- O(1)的平均时间复杂度运行。
示例
输入
 [“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
 [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
 输出
 [null, null, null, 1, null, -1, null, -1, 3, 4]
解释
 LRUCache lRUCache = new LRUCache(2);
 lRUCache.put(1, 1); // 缓存是 {1=1}
 lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
 lRUCache.get(1); // 返回 1
 lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
 lRUCache.get(2); // 返回 -1 (未找到)
 lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
 lRUCache.get(1); // 返回 -1 (未找到)
 lRUCache.get(3); // 返回 3
 lRUCache.get(4); // 返回 4
解题思路
- 首先,函数 get和put以O(1)的平均时间复杂度运行,那么就要使用到hash table进行查询操作。
- hash table中存放什么内容呢?其中- key必然是我们执行查询的- key,那么- value存放什么呢?因为涉及到时间复杂度为- O(1)的驱逐操作,我们考虑使用链表进行维护。你可以将此链表想象为特殊的优先队列。链表中,元素越靠前,那么它就是最近使用的。
- 对于get操作,首先判断key是否存在,不存在就返回-1。如果key存在,那么我们返回元素value。
- 对于put操作,首先判断key是否存在,不存在我们需要构造元素然后将元素插入到链表头部,并且需要维护哈希表。如果key存在,那么我们需要将元素插入到链表头部,并更新哈希表。
C++ 代码
struct DLinkNode {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){}
};class LRUCache {
public:LRUCache(int _capacity) : capacity(_capacity), size(0){head = new DLinkNode();tail = new DLinkNode();head->next = tail;tail->prev = head;}int get(int key) {// if (!cache.count(key)) return -1;if (cache.find(key) != cache.end()) {DLinkNode* node = cache[key];move_to_head(node);return node->value;} else {return -1;}}void put(int key, int value) {if (cache.find(key) != cache.end()) {DLinkNode* node = cache[key];node->value = value;move_to_head(node);} else {DLinkNode* node = new DLinkNode(key, value);cache.insert({key, node});// 其他插入的方法:1. cache[key] = value;  使用索引操作符  2. cache.insert(make_pair(key, node));  使用insert member func 3. cache.empalce(key, node); 使用emplace member funcadd_to_head(node);++size;if (size > capacity) {DLinkNode* removed = remove_tail();cache.erase(removed->key);delete removed;--size;}}}
private:unordered_map<int, DLinkNode*> cache;DLinkNode* head, * tail;int size, capacity;void add_to_head(DLinkNode* node) {DLinkNode* tmp = head->next;head->next = node;node->prev = head;node->next = tmp;tmp->prev = node;}DLinkNode* remove_tail() {DLinkNode* node = tail->prev;tail->prev->prev->next = tail;tail->prev = tail->prev->prev;return node;}void move_to_head(DLinkNode* node) {node->prev->next = node->next;node->next->prev = node->prev;add_to_head(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);*/