C/C++ Arena

Step 5 of 5

Challenge: an LRU cache

A least-recently-used (LRU) cache keeps the capacity most recently used items and evicts the stalest one when full. It sits in front of databases, file systems and web servers everywhere, and it's one of the most common interview questions because it combines two data structures, each covering the other's weakness:

The key tool is list.splice(list.begin(), list, it): it moves the element at it to the front in O(1), without invalidating any iterators, so the map stays correct.

#include <iostream>
#include <list>
#include <string>

int main() {
    std::list<std::string> recent = {"a.txt", "b.txt", "c.txt"};   // front = most recent
    auto it = std::next(recent.begin(), 2);                        // points at c.txt

    recent.splice(recent.begin(), recent, it);                     // c.txt used again
    for (const auto& f : recent) std::cout << f << " ";
    std::cout << "| still valid: " << *it << "\n";

    recent.push_front("d.txt");                                    // a new file opened
    if (recent.size() > 3) {
        std::cout << "evict " << recent.back() << "\n";            // least recent
        recent.pop_back();
    }
    for (const auto& f : recent) std::cout << f << " ";
    std::cout << "\n";
}
c.txt a.txt b.txt | still valid: c.txt
evict b.txt
d.txt c.txt a.txt 

Putting it together

The order in that eviction matters: after pop_back(), the key you needed to erase from the map is gone.

Your turn: write LruCache with std::optional<int> get(int key) (a hit makes the key most recent) and void put(int key, int value) (insert or update, making it most recent; evict the least recent if over capacity). Both O(1).

Previous: Hashing your own keys