October 22, 2007
C++ Hash Table Memoization: Simplifying Dynamic ProgrammingHash Table Refresher
Hash tables were part of the Standard Template Library when the language standard was ratified in 1998. And while most of the Standard Template Library was incorporated into the standard library at that time, the hash_set and hash_map classes were excluded. According to Bjarne Stroustroup Evolving a Language In and For the Real World: C++ 1991-2006:
While these containers will be added to the standard library under the awkward names unordered_map and unordered_set when TR1 is adopted, there is no reason we have to wait that long. Despite the fact that they are missing from the standard, virtually every modern C++ compiler has adopted a reasonable variant of hash_map and hash_set.
The hash_map container does a great job of memoization as described in this article, with a caveat. As I said earlier, you'll need the key to your hash table to be some subset of the input parameters. That's all fine if your key is a single value using a built-in type, such as int, a std::string, or a pointer. These key values are supported implicitly by most implementations of hash_map.
Things get a little more complicated if you are using multiple values or your own structures as a key into the map. Owing to the lack of a standard, implementing non-standard keys requires slightly different techniques, depending on your compiler.
I'll give you examples here that work with the two compilers you are most likely to encounter: Visual C++ .NET 2003/2005, or gcc 3.x.
Let's say you're doing a study tracking peoples reading habits by age, and you want to implement the following code:
class Sample {
public :
Sample( int age=-1, const std::string &genre="" )
: mAge( age )
, mGenre( genre ){}
int mAge;
std::string mGenre;
};
int main()
{
hash_map<Sample,int> AnnualBooksReadByAgeAndGenre;
AnnualBooksReadByAgeAndGenre[ Sample( 15, "Fantasy" ) ] = 15;
AnnualBooksReadByAgeAndGenre[ Sample( 18, "Sports" ) ] = 12;
AnnualBooksReadByAgeAndGenre[ Sample( 35, "Mystery" ) ] = 17;
AnnualBooksReadByAgeAndGenre[ Sample( 42, "Romance" ) ] = 125;
return 1;
}
You won't be able to compile this code as-is, for at least three reasons:
Item 3 is only needed if you are using something other than a basic type for your class, and it's the trickiest. Defining the comparison is necessary so that the hashing library code can verify key equality during lookups or collisions.
In both cases, the function is usually pretty easy to write -- you just compose it using existing functions. Examples for Microsoft and gcc compilers circa 2007 are given below.
|
|
||||||||||||||||||||||||||||||
|
|
|
|