Memoization in C++

The class of Dynamic Programming problems are very interesting. These problems all boil down to a class of optimization problems. Such problems are characterized by the distinctive reduction in their design. This reduction can lead to smaller sub-problems that are solved and the results bubbled up. In essence, dynamic programming problems are solved bottom-up, since the results of the sub-problems drive those above them.

The problem with such a technique lies in the fact that every solution requires you to solve every sub-problem to obtain an optimal solution. Memoization provides a simple and largely effective solution to alleviate this problem by storing results to these overlapping sub-problems for future use. Let’s look at an example using the evergreen fibonacci series:

Inside the guts of Memoization

The naive solution to recursive fibonacci series is :

int fib (int n)
    if( n <=1 )    return 1;
    else           return fib ( n-1 ) + fib ( n-2 );

Let’s look at what happens when we run it for a couple of values :

fib (5) ; // = fib(4)  + fib(3)
          // = (fib(3) + fib(2)) + (fib(2) + fib(1))
          // = ( (fib(2) + fib(1)) + (fib(1) + fib(0)) ) + 
          //               ( (fib(1) + fib(0)) + fib(1))
          // = ( ( (fib(1) + fib(0)) + fib(1)) + 
          //               (fib(1) + fib(0)) ) + ( (fib(1) + fib(0)) + fib(1))
          // 7 '+' operators.

fib (6) ; // 6 overlapping subproblems, 
          // results in '+' operator being run 11 times, 
          // extrapolating from above.

But we already calculated fib (5), didn’t we? And since

fib (6) = fib (5) + fib(4);
fib (5) = fib(4) + fib(3);

We’ve already calculated fib (4) too. So fib (6) needs to just add the 2 values, resulting in just a single ‘+’ operation.

To use this information in our solution, let’s use a global map that stores intermediate solutions. (we can use hash_maps for faster un-ordered  access when the TR1 specification and C++0x is standardized)

std::map<int, int> fibHash;

int memoized_fib (int n)
    std::map<int, int>::iterator fibIter = fibHash.find(n);
    if( fibIter != fibHash.end() ) return *fibIter;

    int fib_val;
    if( n <=1 )    fib_val = 1;
    else           fib_val = memoized_fib ( n-1 ) + memoized_fib ( n-2 );
    fibHash[ n ] = fib_val;
    return fib_val;

This is a fairly one off solution, and requires modifications for using with multiple functions… but with C++0x we can do fully automatic memoization as described here :

Coming up : my feeble attempt at auto-memoization in the current version of C++.


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>