实现一个 LRU 风格的缓存类

需求描述

类似于Windows系统的 win 菜单最近打开功能模块,使用最近最少使用(LRU)的缓存淘汰策略,缓存可以设置最大容量。
get:获取缓存数据,不存在时返回 -1
put:新增或者更新缓存,当容量已满时,删除最早的数据,再插入

class UpdateCaching {
   
	public:
		UpdateCaching(int capacity){
   }
		int get(int key){
   }
		void put(int key ,int value){
   }
}

豆包

解决思路:

  1. 使用 std::unordered_map 存储键值对,以便快速查找和更新数据。(为啥使用 unordered_map 而不是 map

  2. 使用 std::list 存储键的访问顺序,以便在容量满时删除最早的数据。

  3. put 操作中:

    • 检查缓存是否已满,如果已满,删除 list 中的第一个元素,并从 unordered_map 中移除对应的键值对。
    • 将新元素添加到 unordered_map 中,并将键添加到 list 的末尾。
  4. 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 的时间复杂度问题

getput 方法中,使用 keyOrder.remove(key) 来移动元素到列表末尾。std::list::remove 的时间复杂度是 O ( n ) O(n) O(n),因为它需要遍历整个列表来找到要删除的元素。可以通过维护一个指向每个键在列表中位置的映射,将这一操作的时间复杂度优化到 O ( 1 ) O(1) O(1)

2. 代码复用

getput 方法中都有将键移到列表末尾的操作,可以将这一操作提取成一个单独的方法,提高代码的复用性。

优化后的代码
#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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值