Memoization is a programming technique that saves the result of a function call so that future calls with the same inputs can return the stored result instead of recomputing it. It is a targeted form of caching applied at the function-call level: when a function is invoked, its inputs are used as a key into a table; if a matching entry exists the stored result is returned immediately, otherwise the function runs and its result is recorded for later reuse. Memoization is frequently used to speed up expensive or repetitive computations and to eliminate redundant work in recursive algorithms.
How it works
At its core memoization maintains an associative structure (often a hash table or dictionary) that maps argument tuples to results. Typical implementation steps are: on call, construct a key from the arguments; check the table for an entry; if present return it; if not, compute, store, then return. Implementations vary in how they create keys, handle mutable arguments, and manage storage size. Many languages provide simple idioms or utilities (for example decorators or higher-order wrappers) that apply memoization to existing functions without changing their bodies.
Characteristics and common variants
- Pure-function fit: Memoization is safest for functions without side effects and whose results depend only on inputs.
- Keying strategies: Keys can be argument tuples, canonicalized representations, or hashes; arguments that are mutable or unhashable require special handling.
- Eviction policies: Because memory is finite, strategies such as least-recently-used (LRU) or time-to-live can remove old entries.
- Thread-safety: Concurrent environments need synchronization to avoid races when populating the table.
History and relation to other concepts
Memoization grew from practical needs to avoid repeated computation and is closely related to general caching. However, memoization specifically refers to storing results of deterministic function calls, rather than caching arbitrary resources (like disk pages or buffers). For contrast, see discussions of broader caching strategies. In some logic and rule-based systems memoization is called tabling; see tabling in logic programming. Memoization is also often described alongside lookup tables and other precomputation techniques (lookup table).
Uses and examples
Memoization is commonly used to accelerate:
- Recursive computations such as naive Fibonacci or combinatorial counts, where overlapping subproblems exist.
- Dynamic programming: memoized top-down approaches are an alternative to bottom-up tabulation.
- Expensive pure computations like parsing, numeric integration, or deterministic query results.
It is often introduced as a simple optimization: wrap a function, store computed values, and skip recomputation for repeat inputs. Many language standard libraries or third-party modules provide utilities to memoize functions, and tutorials on program optimization frequently include memoization as a first technique to learn.
Benefits and limitations
- Benefits: Reduced CPU time for repeated calls, straightforward to add to many functions, improves responsiveness for interactive computations.
- Limitations: Additional memory usage, complexity when arguments are mutable or non-deterministic, and potential for stale results if external state affects output.
In practice, memoization is a pragmatic trade-off between time and space. When used appropriately—particularly for pure, deterministic functions with a limited or frequently repeated input domain—it can yield large performance gains with modest engineering effort. For broader alternatives and deeper background, readers may consult materials on lookup tables and caching techniques, and examine language-specific facilities for memoization and tabling.