2

I understand that unordered_map<T, int> would be more efficient when retrieving a value from the key O(1), than map<T, int> would be O(lg n) regarding the performance.

However, I found that unordered_map<T, int> does not support as many types as map<T, int> does.

For instance, map<pair<int, int>, int> is OK, but unordered_map<pair<int, int>, int> is not.

I am wondering is there any underlying difficulty for this? If the performance is concerned, what data structure could I use to get a hashtable of key-type pair with O(1) performance.

CrepuscularV
  • 983
  • 3
  • 12
  • 25
  • It isn't clear if you're asking why it doesn't work out of the box, or want to know how to make it work. The answers so far address the latter. – juanchopanza May 16 '14 at 06:29
  • @juanchopanza, Very good point. I updated to try to address the first question. – merlin2011 May 16 '14 at 06:32
  • 1
    @merlin2011 Well, I would have interpreted as asking "why is `std::hash` not specialized for `std:pair` where `T` is a type for which `std::hash` *is* specialized :-) – juanchopanza May 16 '14 at 06:35
  • This is a better duplicate: http://stackoverflow.com/a/7222201/390913 – perreal May 16 '14 at 06:37

3 Answers3

0

The reason why it does not work out of the box is because the type pair<T,T> does not define a hash function and unordered_map is essentially a hash map, so its keys must be hashable.

There is nothing fundamentally wrong with unordered_map<pair<int, int>, int>. The problem is that you need to provide a hash function and a comparison function for equality.

See this question for your specific case of <pair,pair> as key and this answer for more details on the general case.

Community
  • 1
  • 1
merlin2011
  • 71,677
  • 44
  • 195
  • 329
0

You can define a custom hash function:

#include <unordered_map>

typedef std::pair<int,int> int_pair;
class MyHashFunc {
    std::hash<int> int_hash_func;
    public:
        long operator()(const int_pair &k) const{

            return (int_hash_func(k.first) << 16) + (int_hash_func(k.second));
        }
};

int main() {
    std::unordered_map<int_pair, int, MyHashFunc> m;
    return 0;
}
perreal
  • 94,503
  • 21
  • 155
  • 181
-1

If you can provide a way to generate a hash from pair<int, int>, then you can use it.

Example:

#include <unordered_map>
#include <utility>
using namespace std;

struct IntPairHash
{
   size_t operator()(pair<int, int> const& p)
   {
      // If you have a 64 bit platform where sizeof(size_t) == 64
      // and sizeof(int) == 32, you can use:
      size_t h = p.second;
      h <<= 32;
      h += p.first;
      return h;

      // For other platforms, a more different approach to come up with
      // a hash value for p must be devised.
   }
};

void foo()
{
   unordered_map<pair<int, int>, int, IntPairHash> a;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    `h <<= 32;` - if `sizeof(size_t) == sizeof(int)` you've just thrown away `p.second` completely... better to `xor` with say `(h << 1) ^ (h >> 1)` though for `sizeof(size_t) == 2 * sizeof(int)` it would leave the high order bits 0, that's less likely to be important when modded/anded into a hash table bucket count. – Tony Delroy May 16 '14 at 06:35
  • @TonyD Point well made. I updated my answer to add that caveat. – R Sahu May 16 '14 at 16:04