What is memoization and where is it useful? Let us do a quick overview and dig into example code.
Memoization is a technique that can be used in long, recursive code to cache results from previous executions and speed up the overall process.
Consider a long repetitive operation where there is a good possibility that you will have the same arguments for the computation function more than once. What if we could make our program remember what had transpired in the last execution. We could then effectively shave-off cycles that had been done previously and speed up execution.
This is “memoization”.
We have seen in other posts that closures can remember parent’s state. Putting the two together, we can see a potential use of closures in memoization.
A practical example
Consider the totally practical problem of getting Fibonacci series up to a given number.
fibo(5) = [1, 1, 2, 3, 5]
Each number is equal to the sum of the previous two numbers, and the series starts from 0
or 1
. We can generate the series using simple recursion.
|
|
The recursion counts down numbers while also adding results. So, you end up calling the function with same numbers more than once.
fibo(5) calls => fibo(4), fibo(3)
fibo(4) calls => fibo(3), fibo(2)
fibo(3) calls => fibo(2), fibo(1)
..
For an input 5
, the following function calls happen -
|
|
Memoization helps avoid evaluating the function evaluation for repeat calls. We will rewrite the above function to calculate Fibonacci series -
|
|
We have done a really simple change - added an object called cache
that persists across function calls. Each time there is an evaluation, the result is added to cache
.
The recursion happens as normal for the first call.
For e.g. fibo(5)
-
- Evaluate expression
fibo(4)
+fibo(3)
- Store results for
2
,1
in cache - Return results
For the next iteration - for fibo(4)
:
- The expressions are
fibo(3)
+fibo(2)
3
already exists in cache, and cache results are returned- Evaluation for
fibo(2)
happens normally
We can also see from the output that repeating instances will now not retrigger the full function, but return results from cache. (applicable for 1
, 2
, 3
as seen previously).
The new flow is -
- Initiate program to calculate Fibonacci series for 5
- Initiate
cache
- Add given input number (e.g. n-1) and its evaluation result to cache
- Recursion with expression
fibo(n-1) + fibo(n-2)
to count down till number 1 - If evaluation already exists, return cached result. As a result
fibo(1)
,fibo(2)
andfibo(3)
are returned from cache when called the second time
When to use memoization?
When there is a long, oft-repeated evaluation cycle in your code. Make your code faster by utilizing cached results rather than full evaluation in a function.