Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to hash an unordered_map?

boost::hash has hashing functions for most builtin types including containers.

But as stated in the boost::hash_range function description, the hash algorithm for ranges

is sensitive to the order of the elements so it wouldn't be appropriate to use this with an unordered container

And thus there is no boost::hash specialization for std::unordered_map nor boost::unordered_map.


The question is:

Is there an "easy and efficient" way to hash an unordered_map without reimplementing a hash algorithm from scratch ?

like image 359
Drax Avatar asked Aug 11 '14 14:08

Drax


People also ask

Which hashing is used in unordered_map?

The unordered_map::hash_function() is a built in function in C++ STL which is used to get the hash function. This hash function is a unary function which takes a single argument only and returns a unique value of type size_t based on it.

Is unordered_map a hash map?

Yes, HashMap in java and unordered_map in c++ stl are more or less the same… you can store pointers in java too(Don't forget, in java, everything you deal with is a reference)… hence, HashMap also serves your purpose.

Is unordered_map a hash table?

Unordered_map IS a hash table actually. You may want to use a better example as, as is the second insert will fail since it has the same key.

Can you iterate over unordered_map?

Iterating over a map by using STL Iterator: By creating an iterator of std::map and initializing it to the starting of map and visiting upto the end of map we can successfully iterate over all the elements of map.


2 Answers

The problem here is that there is no guarantee that the items even have an ordering among them.
So, sorting the items may very well not work for arbitrary unordered containers. You have 2 options:

  1. Just XOR the hashes of all the individual elements. This is the fastest.
  2. First sort the hashes of the containers, and then hash those. This may result in a better hash.
like image 169
user541686 Avatar answered Oct 02 '22 11:10

user541686


You can of course convert the unordered_map to some other data structure that has a guaranteed order and use that to generate the hash.

A better idea might be to hash each individual element of the map, put those hashes into a vector, then sort and combine the hashes. See for example How do I combine hash values in C++0x? to combine the hashes.

template<typename Hash, typename Iterator>
size_t order_independent_hash(Iterator begin, Iterator end, Hash hasher)
{
    std::vector<size_t> hashes;
    for (Iterator it = begin; it != end; ++it)
        hashes.push_back(hasher(*it));
    std::sort(hashes.begin(), hashes.end());
    size_t result = 0;
    for (auto it2 = hashes.begin(); it2 != hashes.end(); ++it2)
        result ^= *it2 + 0x9e3779b9 + (result<<6) + (result>>2);
    return result;
}

Testing this on shuffled vectors shows that it always returns the same hash.

Now to adapt that basic concept to work specifically with unordered_map. Since the iterator of unordered_map returns a pair, we need a hash function for that too.

namespace std
{
    template<typename T1, typename T2>
    struct hash<std::pair<T1,T2> >
    {
        typedef std::pair<T1,T2> argument_type;
        typedef std::size_t result_type;

        result_type operator()(argument_type const& s) const
        {
            result_type const h1 ( std::hash<T1>()(s.first) );
            result_type const h2 ( std::hash<T2>()(s.second) );
            return h1 ^ (h2 + 0x9e3779b9 + (h1<<6) + (h1>>2));
        }
    };

    template<typename Key, typename T>
    struct hash<std::unordered_map<Key,T> >
    {
        typedef std::unordered_map<Key,T> argument_type;
        typedef std::size_t result_type;

        result_type operator()(argument_type const& s) const
        {
            return order_independent_hash(s.begin(), s.end(), std::hash<std::pair<Key,T> >());
        }
    };
}

See it in action: http://ideone.com/WOLFbc

like image 41
Mark Ransom Avatar answered Oct 02 '22 12:10

Mark Ransom