Contents

Computer Science › Data Structures · also in Caching

LRU Cache

A cache evicting the least recently used item, built from a hash map and a linked list.

Also known as: LRU, least recently used cache

An LRU cache keeps a fixed number of items and evicts the least recently used one when it needs room. Each get or put marks the item as recently used. A hash map finds items quickly, and a doubly linked list keeps them in order from most to least recently used, so both operations take constant time on average.

Python’s OrderedDict keeps this order for you:

from collections import OrderedDict

class LRU:
    def __init__(self, capacity):
        self.capacity = capacity
        self.items = OrderedDict()

    def get(self, key):
        if key not in self.items:
            return None
        self.items.move_to_end(key)          # now the most recently used
        return self.items[key]

    def put(self, key, value):
        if key in self.items:
            self.items.move_to_end(key)
        self.items[key] = value
        if len(self.items) > self.capacity:
            self.items.popitem(last=False)   # drop the least recently used

c = LRU(2)
c.put("a", 1); c.put("b", 2)
c.get("a")
c.put("c", 3)          # "b" is evicted

The OrderedDict is a hash table with a linked list of its own, so this is the same structure built in. A hand-written version uses a dict plus a doubly linked list, as described in the doubly linked list concept.

The trade-off is that the structure is only as good as the access pattern. An LRU cache helps when recently used items are likely to be used again soon. For a workload that scans through many items once, it can evict everything useful, and a different policy may do better.

The classic mistake is treating an LRU cache as thread-safe, or as a substitute for correct invalidation. When the underlying data changes, cached entries must be removed or refreshed, or the cache serves stale answers. For the wider design, see caching.