实现一个缓存类
需求描述
类似于Windows系统的 win 菜单最近打开功能模块,使用最近最少使用(LRU)的缓存淘汰策略,缓存可以设置最大容量。
get:获取缓存数据,不存在时返回 -1
put:新增或者更新缓存,当容量已满时,删除最早的数据,再插入
class UpdateCaching {
public:
UpdateCaching(int capacity){
}
int get(int key){
}
void put(int key ,int value){
}
}
豆包
解决思路:
-
使用
std::unordered_map
存储键值对,以便快速查找和更新数据。(为啥使用 unordered_map 而不是 map) -
使用
std::list
存储键的访问顺序,以便在容量满时删除最早的数据。 -
在
put
操作中:- 检查缓存是否已满,如果已满,删除 list 中的第一个元素,并从
unordered_map
中移除对应的键值对。 - 将新元素添加到
unordered_map
中,并将键添加到list
的末尾。
- 检查缓存是否已满,如果已满,删除 list 中的第一个元素,并从
-
在
get
操作中:- 使用
unordered_map
查找键是否存在,如果存在,将键移到list
的末尾,表示最近访问过。
- 使用
实现代码:
#include <iostream>
#include <unordered_map>
#include <list>
class UpdateCaching {
private:
std::unordered_map<int, int> cache;
std::list<int> keyOrder;
int capacity;
public:
UpdateCaching(int cap) : capacity(cap) {
}
int get(int key) {
if (cache.count(key) == 0) {
return -1;
}
// 将访问的键移到列表末尾,表示最近使用过
keyOrder.remove(key);
keyOrder.push_back(key);
return cache[key];
}
void put(int key, int value) {
if (cache.count(key) > 0) {
// 键已存在,更新值并将其移到列表末尾
cache[key] = value;
keyOrder.remove(key);
keyOrder.push_back(key);
return;
}
if (cache.size() >= capacity) {
// 缓存已满,移除最久未使用的元素
int oldestKey = keyOrder.front();
keyOrder.pop_front();
cache.erase(oldestKey);
}
// 插入新元素
cache[key] = value;
keyOrder.push_back(key);
}
};
int main() {
UpdateCaching cache(3);
cache.put(1, 10);
cache.put(2, 20);
cache.put(3, 30);
std::cout << cache.get(2) << std::endl; // 输出 20
cache.put(4, 40); // 缓存已满,删除最早的元素 (1, 10)
std::cout << cache.get(1) << std::endl; // 输出 -1
return 0;
}
优化1
1. std::list::remove
的时间复杂度问题
在 get
和 put
方法中,使用 keyOrder.remove(key)
来移动元素到列表末尾。std::list::remove
的时间复杂度是 O ( n ) O(n) O(n),因为它需要遍历整个列表来找到要删除的元素。可以通过维护一个指向每个键在列表中位置的映射,将这一操作的时间复杂度优化到 O ( 1 ) O(1) O(1)。
2. 代码复用
get
和 put
方法中都有将键移到列表末尾的操作,可以将这一操作提取成一个单独的方法,提高代码的复用性。
优化后的代码
#include <iostream>
#include <unordered_map>
#include <list>
class UpdateCaching {
private:
std::unordered_map<int, int> cache;
std::unordered_map<int, std::list<int>::iterator> keyIterators;
std::list<int> keyOrder;
int capacity;
// 将键移到列表末尾
void moveToBack(int key) {
auto it = keyIterators[key];
keyOrder.erase(it