编程笔记 - LRU Cache

当缓存容量固定时,我们需要一种淘汰策略:每次访问把数据标记为“最近使用”,当容量满了时淘汰“最久未使用”的那个,以提升缓存命中率。这就是 LRU 的核心。

以下是一个使用 C++ 实现的 LRU Cache 模版,拥有以下特性:

  • 使用 std::list 维护一个缓存列表,头部的缓存块为最近使用的、尾部的缓存块为最久未使用的。每次读写都会将对应的缓存块提到头部,时间复杂度为 \(O(1)\)
  • 使用 std::unordered_map 维护一个查找表,根据关键字快速查找缓存块在列表中的位置,时间复杂度为 \(O(1)\)
#include <list>
#include <unordered_map>

template<typename K, typename V>
class LRUCache {
public:
    LRUCache(size_t capacity) : _cap(capacity) {
        if (_cap <= 0)
            throw "ERROR: capacity must be > 0";
    }
    ~LRUCache() = default;

    std::unique_ptr<V> get(const K& key) {
        if (!_lookup.count(key)) {
            return nullptr;
        }
        auto it = _lookup[key];
        update(it);
        return std::make_unique<V>(it->second);
    }

    void put(const K& key, const V& value) {
        if (_lookup.count(key)) {
            auto it = _lookup[key];
            it->second = value;
            update(it);
            return;
        }
        if (_lru.size() == _cap) {
            int k = _lru.back().first;
            _lookup.erase(k);
            _lru.pop_back();
        }
        _lru.push_front({key, value});
        _lookup[key] = _lru.begin();
    }

private:
    using node_t = std::pair<K, V>;
    using iter_t = typename std::list<node_t>::iterator;

    size_t _cap;
    std::list<node_t> _lru;
    std::unordered_map<K, iter_t> _lookup;

    void update(iter_t it) {
        _lru.splice(_lru.begin(), _lru, it);
    }
};
posted @ 2025-09-03 17:02  WenbinTeng  阅读(8)  评论(0)    收藏  举报