### Arpa's blog

By Arpa, history, 6 years ago,

UPD: Tricks to make unordered_map faster added.

Hi!

##### What is unordered_map?

It is a data structure like map but it is more than 4 times faster than map.you can use it in C++11 with including #include<unordered_map>.for example:

#include<unordered_map>
using namespace std;
int main(){
unordered_map<int,int>mp;
mp[5]=12;
mp[4]=14;
cout<<mp[5]<<' '<<mp[4]<<endl;//prints: 12 14
}


Lets explain it more.

##### How it works?

Focus on unordered_set for simplify.You can imagine that it has vector of vector like vector<vector<type> > mp. Every time you insert value V in that, it calculate its hash(I will explain how it works), let hash(V)=K; it inserts V into mp[K] (formally it calls mp[K].push_back(V)).When you call mp.count(V) it searchs for V in mp[K].

##### map VS unordered_map (and set VS unordered_set)

1-unordered_map is more than 4 times faster

Focus on problem 527E - Data Center Drama, it seems that it is good to use unordered_map instead of map.

My submission with map: 14269000 Time:484 MS.

My submission with unordered_map: 14269381 Time:358 MS.

Another good sample to show how fast is unordered_map is problem 178C3 - Smart Beaver and Resolving Collisions:

My submission with map: 15781810 Time limit exceeded on test 36 .

My submission with unordered_map: 15774685 Accepted (Time:966 MS).

2-unordered_set (and unordered_map) is not sorted

Please note that set (and map) is sorted, for example *(s.begin()) is always smallest number in the set; but in unordered_set it isn't. similarly there isn't lower_bound and upper_bound in unordered_set (and unordered_map similarly).

##### Creating hash function for structs

Now, one other problem remains, you can try to compile this code:

unordered_map<pair<int,int>,int>mp;


You will get Compilation Error! Why? See this page for unordered_map supported types. For unsupported types, you have to create your own hash function for use. For example lets see how we can create a hash function for pair<int,int>.

As you know any int value is between -2^31+1 to 2^31-1.so if we create function that for every pair<int,int> returns distinct value in type size_t(alias of unsigned int), it will be done. It is pretty easy: x.first^(x.second<<32) is good. but be careful about overflow ;for having good hash function we use hash<long long>.The code is looks like this:

struct HASH{
size_t operator()(const pair<int,int>&x)const{
return hash<long long>()(((long long)x.first)^(((long long)x.second)<<32));
}
};
unordered_map<pair<int,int>,int,HASH>mp;


Now you have a unordered_map of pair<int,int> (it isn't problem what is second member, in example it was int).Creating hash function for other structs is same.

##### How to test unordered_map is faster than map?

You can test that for N=10^6, unordered_set(unordered_map) is more than 4 times faster than set(map) ;with this code:(compile code with command: g++ file.cpp -std=c++11 -O2)

#include <bits/stdc++.h>
using namespace std;
unordered_set<int>s;//replace it with set for test.
int main(){
auto T=clock();
s.reserve(32768); //updated !
for(int i=0;i<1000000;i++)
s.insert(i);
cout<<double(clock()-T)/CLOCKS_PER_SEC<<'\n';
}


Note1: Let your hash function H(V), it is better that H(V) returns distinct value for every distinct V, it makes unordered_map faster; but if you can't do that it doesn't problem. The only problem is that unordered_map becomes slower(however it is better than map).

Note2: Please be careful about your hash function time complexly! it is fun to use this hash function:

struct HASH{
size_t operator()(const pair<int,int>&x)const{
size_t ans=0;
for(int i=0;i<x.first;i++)
ans+=x.second;
return ans;
}
};


UPD I will explain hash<type> in my next post.

UPD It seems that sometimes unordered_map becames so slow.but it can improve with this two lines of code:

unordered_map<int,int>mp;
mp.reserve(1024);


With this two lines unordered_map become about 10 times faster. You can replace 1024 with another suitable power of two.(it depends on number of insert s you will do).

• +47

 » 6 years ago, # |   0 Thank you so much! I had no idea about this. From now I'll use it as much as possible :)
•  » » 6 years ago, # ^ | ← Rev. 2 →   -6 you can use unordered_set/map when you don't need order of members.for example one of unordered_set applications is when you are storing all of the settings of one vector (for example); you can store them in unordered_set.for example: unordered_set >all; int count(vectorv){ if(all.count(v)) return 0; all.insert(v); ... } you will never check the same vectors with that trick!
 » 6 years ago, # |   0 Unordered_map isn't faster than map when count of elements isn't much. Sorry for bad eng :)
•  » » 6 years ago, # ^ | ← Rev. 2 →   +1 if N is about 100 ;map has equal time with unordred_map.but you can test it when N is about 10^6. it seems that unordered_map is about 4 times faster than map.
•  » » » 2 years ago, # ^ | ← Rev. 3 →   0 Hi, I need a small clarification. I was just solving this problem. I made submission using both unordered_map and map. But when I include the reserve and max_load_factor, my code gets AC I don't understand why the normal unordered_map gives TLE when N is about 1e5 when it's supposed to be faster than map. Could you please help me with this? Is it because of "sometimes unordered_map becomes so slow" ?
•  » » » » 2 years ago, # ^ | ← Rev. 2 →   0 yeah unordered_map gives O(1) only when input is truly randomized otherwise it can give O(n) time complexity.i think input here is causing collision and worst case is taking it's toll.i have used custom hash blogged by neal and it is giving AC. see the slight tweaking of your code: code#include typedef long long ll; using namespace std; struct neal { static uint64_t splitmix64(uint64_t x) { x += 0x9e3779b97f4a7c15; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return x ^ (x >> 31); } size_t operator()(uint64_t x) const { static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x + FIXED_RANDOM); } }; ll lcm(ll val1,ll val2) { if(val1==0||val2==0) return 0; else return (val1*val2)/__gcd(val1,val2); } ll pw(ll base,ll p) { if(base==1||p==0) return 1; if(p%2==0){ ll interm=pw(base,p/2); return interm*interm; } else return base*pw(base,p-1); } int main() { ll n,k,x; dequedq; unordered_mapm; cin>>n>>k; for (ll i = 0; i < n; i ++) { cin>>x; if (m[x]) continue; else { if (dq.size() < k) { dq.push_front(x); m[x] = 1; } else { ll p = dq.back(); m[p] = 0; dq.pop_back(); dq.push_front(x); m[x] = 1; } } } cout<
•  » » » » 14 months ago, # ^ | ← Rev. 2 →   0 Hey AishwaryaRWhen the capacity is not reserved beforehand, it takes capacity as 16 and creates a hashtable on this.Everytime the number of elements increase than threshold, it doubles this capacity and rehashes all the existing keys.Reserving an approximate capacity before hand avoids this rehashing and dynamic space allocation, in turn making the program more efficient and reducing the runtime.
•  » » » » » 14 months ago, # ^ |   0 Thank you so much for that clarification!
 » 6 years ago, # |   +28  size_t operator()(const pair&x)const{ return ((long long)x.first)^(((long long)x.second)<<32); } Most competitive programming environments are still 32-bit. So, by doing ^(((long long)x.second)<<32) and then implicitly casting to size_t, you are effectively discarding x.second. Now, the hash depends only on x.first.Here is the code to check that: #include using namespace std; struct HASH{ size_t operator()(const pair&x)const{ return ((long long)x.first)^(((long long)x.second)<<32); } }; unordered_map,int,HASH>m; int main(){ auto T=clock(); for(int i=0;i<20000;i++) m[make_pair (1, i)] = i; cout<
•  » » 6 years ago, # ^ | ← Rev. 5 →   -23 Post edited.
•  » » » 6 years ago, # ^ |   +11 Sorry, I don't get what you are saying. I think you have to work on your math. 858 is smaller than 1000; isn't it? So what? That's still on the order of a second.Note that we insert 20,000 elements, not a million like you do. If inserting twenty thousand, again, elements takes on the order of a second, that's quadratic behavior, or at least definitely not linear. The constant 20,000 is used instead of your code's 1,000,000 so that we can actually see the result in reasonable time. One can make it 1,000,000 and watch it time out (I, for one, wasn't patient enough to let it finish).Also, note that changing make_pair (1, i) to make_pair (i, i) makes the program run in an instant (less than 100 ms). To summarize again: Codeforces checks your solutions in a 32-bit environment. So, size_t is 32 bits long. So, for every possible X and Y, the result of X ^ (((long long)Y)<<32) converted to size_t is just X. So, the hashes for pairs (1, 0), (1, 1), (1, 2), (1, 3), ..., (1, 999999) will be equal, and unordered_map will have trouble storing them.
•  » » » » 6 years ago, # ^ | ← Rev. 2 →   0 I have interested! thank you.I have changed my hash function, you can see the new one.I have mistaken, size_t is alias of unsigned int, no unsigned long long int.
•  » » » » » 6 years ago, # ^ |   0 The new hash approach perhaps does something like x * 37 + y anyway, so why not do that explicitly? struct HASH{ size_t operator()(const pair&x)const{ return (size_t) x.first * 37U + (size_t) x.second; } }; On a side note, I'm surprised that a language as mature as C++ (11) does not define a default hashing method for library containers such as pair or vector.
•  » » » » » » 6 years ago, # ^ | ← Rev. 2 →   +5 It has one for vector: hash >.You can use it for pair, first create a vector of {x.first,x.second} and use hash >.
•  » » » » » » » 6 years ago, # ^ |   0 Can you please elaborate?I try the following: #include using namespace std; unordered_set , hash > () > s; int main() {s.insert ({1, 2, 3});} And it does not compile (MinGW GCC 4.8.1 and 5.1.0), throwing some 100+ lines of error messages at me, basically stating that I misuse hash >. Removing () after hash > does not help.Googling for a few minutes did not help me either. I only found a reference stating that it is not implemented in the library, and a few implementations for custom types.
•  » » » » » » » » 6 years ago, # ^ |   0 You can create it like this: namespace std{ template<>struct hash >{ size_t operator()(vector const& v) const{ unsigned long long h=0; for(auto &x:v) h<<=32,h^=hash()(x),h=hash()(h); return h; } }; } 
•  » » » » » » » » » 6 years ago, # ^ |   0 So, what you are saying is that there is in fact no built-in hash > after all? Then my point still stands.I won't deny that almost anything is possible with C++. I'm just surprised some trivial pieces of that work aren't in the library already.
•  » » 5 years ago, # ^ | ← Rev. 3 →   0 if i want to declare an unordered map like that unordered_map< pair ,int> frq; example : it is something like that : frq[ ( (2,3) , 5 ) ];Or if i want to declare an unordered map like that unordered_map< pair ,pair > frq; example : it is something like that => frq[( (2,3) , (4,5) ) ];How can i write my own hash function ?
•  » » 18 months ago, # ^ |   +10 Hey Gassa! Would you recommend same struct HASH when the order of elements in my pair doesn't matter? for example, in my case pair (1, 2) can be considered same as (2, 1). Is there any faster way for that?
•  » » » 18 months ago, # ^ |   0 When you store the pairs, always make it such that pair.first <= pair.second holds.
•  » » » 18 months ago, # ^ |   0 In fact, my point above was that I don't like the very idea of C++ not having a standard hash of pair in the library, and the 95%+ horrendous implementations of pair hashing that ensue. Plentiful examples around or on StackOverflow.In particular, no, I don't recommend hashing by just XORing the elements of the pair, as there are naturally occurring cases when it results in suboptimal behaviour.As for hashing a pair where the order of elements doesn't matter, I'd do that explicitly at first opportunity: when constructing the pair. So that (a, b) becomes (min(a,b), max(a,b)) right away. And then use standard pairs.
•  » » » » 18 months ago, # ^ |   +10 Thank you. I get it now.
 » 6 years ago, # |   0 I run these two versions of map and unordered_map on custome test with GNU G++11 5.1.0. I see that unordered_map is slower than mapVersion of map: #include using namespace std; map,int>m; int main(){ auto T=clock(); for(int i=0;i<1000000;i++) m[make_pair (1, i)] = i; cout< using namespace std; struct HASH{ size_t operator()(const pair&x)const{ return ((long long)x.first)^(((long long)x.second)<<32); } }; unordered_map,int,HASH>m; int main(){ auto T=clock(); for(int i=0;i<1000000;i++) m[make_pair (1, i)] = i; cout<
•  » » 6 years ago, # ^ | ← Rev. 7 →   0 On Intel® Core™ i3 CPU M 390 @ 2.67GHz × 4 :map : 2469 MSunordered_map: 485 MSOn CodeForces:map: 2469 MSunordered_map : 1885 MS
•  » » » 4 years ago, # ^ |   0 hey @Arpa can u explain me the struct HASH code? thanks in advance.....
•  » » » » 4 years ago, # ^ |   0 You should implement operator () for this struct. It takes an object and returns size_t (alias of unsigned int). You should write it in a way such that minimize the number of conflicts.
•  » » 6 years ago, # ^ |   0 Add this two lines: m.reserve(4096); m.max_load_factor(0.25); 
 » 6 years ago, # |   0 Auto comment: topic has been updated by Arpa (previous revision, new revision, compare).
 » 6 years ago, # | ← Rev. 3 →   0 What does this mean ? s.max_load_factor(0.25);And which library it uses ?
•  » » 6 years ago, # ^ | ← Rev. 3 →   0 The load factor is the ratio between the number of elements in the container (its size) and the number of buckets (bucket_count). (source)it uses (or ) for sure.
 » 6 years ago, # |   +5 Hi can anyone explain, why map is more than 10 times faster in this case? I could not find any reason for this. any help on this matter would be highy appreciated. I also tried adding the 2 lines of code mentioned above to make unordered_map faster but with no luck. 21740384 and 21740655
•  » » 6 years ago, # ^ |   +5 Because map has a logarithmic access time on size always, on the other hand, unordered_map in average has a constant access time, but in worst case it's just linear in size.
•  » » » 6 years ago, # ^ | ← Rev. 3 →   0 Thanks for the quick reply! I am aware of the worst case complexity of unordered map. However, usually most of the times unordered map is observed to be faster. Can you share any further insights on deciding between unordered map and map. And also what is making unordered map slower than map in the above case I presented? i,e.. what kinds of data is suitable to be represented by map and unordered_map exactly?EDIT: I see that the test case on which unordered map gave TLE involves hashing a multiple of some fixed number. Has this got something to do with the TLE(I believe it must be the reason). Also, was the testcase specifically designed so that unordered_map fails on it, How do we make sure not to fall in such traps if so?
 » 6 years ago, # |   0 Please see the following issue: http://codeforces.com/blog/entry/44705?#comment-292160
•  » » 6 years ago, # ^ |   0 Thanks a lot! I'm sorry for posting on the wrong blog. I should have found that post myself. But I'm new here :D
•  » » 6 years ago, # ^ |   0 This problem can resolved with reserve trick.Like this : 21771219.
•  » » » 6 years ago, # ^ |   +8 It's not a trick if you know how unordered_map works.
•  » » » » 6 years ago, # ^ | ← Rev. 2 →   -8 I know how it works. Read post again carefully.I have explained in post how it works.
 » 5 years ago, # |   0 Hi Arpa,Is there any way to limit the size of the map? I mean for example not to allow for the map to contain more than 256 elements? Is there any built in solution for this. Somewhere I've seen before that it have been used like this: unordered_map map_name(256);Is this valid?Thank you in advance.
 » 5 years ago, # |   +2 Hi. I have 3 questions. Why must the input value for the reserve() method be a power of 2? Is there formula to determine the input value for the reserve() method? Let's say we use mp.reserve(x) where x is a power of 2. Does that mean that x must be >= N, where N is the number of elements that we are going to input into the unordered_map? How did you determine the value for the max_load_factor? Is that supposed to be a magic value? Please advise me.
 » 5 years ago, # |   +18 Thank you for your hard work, but unfortunately I don't find it that much useful with all that painful implementation.
 » 4 years ago, # |   0 AC using map: 33860000TLE using unordered_map: 33860168 [ Yes, I used the tricks you mentioned to make unordered map faster. Also I have used the Hash function that you gave in the post for pairSo, how can I believe that unorded_map is faster than map ??
•  » » 4 years ago, # ^ |   0 It's really confusing when to use unordered_map and when to use map. My submission with map takes 1450 ms: 38906751 Same submission with unordered_map takes 467 ms:38906911 Though both passed time limit (3 s), if the time limit was 1-1.3 s, solution using map would have failed.
•  » » 4 years ago, # ^ |   0 You just need to use a better hash function for pair to get your solution passed. The hash function proposed here for pair clearly isn't a good one. Read the above discussion here. I have changed your hash function and your TLE code gets ac for that problem. Here's the ac code with modified hash function.
•  » » » 4 years ago, # ^ |   0 But is it always safe to use unordered_map in contests, since in worst case unordered_map can be of O(n)? Should anyone use unordered_map always instead of map ?
 » 4 years ago, # |   0 SUMFOUR — 4 values whose sum is 0 on SPOJ in an example where unordered_map with reserve() will give AC and others will give TLE
 » 4 years ago, # |   +3 ََُArpa youre the best :)
 » 3 years ago, # |   0 unordered_map with pair as the key recently gave my time out in my code. I used simple map instead of unordered_map and the code was accepted. The worst case space requirement for the problem was O(n^2) with n <= 1000.My submissions are: map and unordered_map.
 » 2 years ago, # |   0 I have used unordered_map for this problem. Christmas Trees I got a TLE with this Then I changed the unordered_map to just map and got AC with this Can you explain what is happening here. [Sorry for my bad English]
 » 2 years ago, # |   -6 Unordered_map : TLE submission linkmap : AC submission linki've no idea why...
•  » » 2 years ago, # ^ |   +3 It happens. Try to use the reserve method. You can implement Hash Map on your own too.
•  » » » 2 years ago, # ^ |   0 Hi. Could you please explain how you arrive with values such as 1024 or 4096 while using reserve? Say, for example, I know that in my program there will be 10^7 insert operations. What value do I use then?Doesn't reserve(4096) mean set the appropriate number of buckets to hold at least 4096 elements in the hash table without exceeding the max_load_ratio?
 » 2 years ago, # |   0 Be careful with hash data structures. Even though std::unordered_map is often faster than std::map, it still has a worst case complexity of O(n) per operation and it is possible to design TLE hacks this way. See https://codeforces.com/blog/entry/62393.
 » 22 months ago, # |   0 Can you tell according to constraint what should be the value in reserve???
 » 21 month(s) ago, # |   0 What is unordred_map?Shouldn't it be "What is unordered_map?"
•  » » 21 month(s) ago, # ^ |   0 Thanks. Fixed.
 » 21 month(s) ago, # |   0 what is the average time complexity of insertion/search in unordered_map if key is string ? Is it O(L) L=>length of string ?
•  » » 21 month(s) ago, # ^ |   0 Yes.
 » 20 months ago, # |   0 Hi I have tried to change (unordered_)map to many thing like this ones but every time I get TLE on last testcase; I think this idea should be change but if anybody can help me, I ll be happy. link of submission
 » 13 months ago, # | ← Rev. 2 →   0 A great article, many thanks to you.Just one thing I would like to add.Imagine you need to have unordered_map< vector < string >, int>. So you can you this hash function for that purpose: struct hasher { size_t operator()(const vector& v) const { vector vs{}; int prime = 31; long long mod = 1e9 + 9; size_t hash = 0; for(string s: v) { long long string_hash{}; long long pow = 1; for(int i = 0; i < s.length(); ++i) { string_hash = (string_hash + (s[i] - '0' + 1) * pow) % mod; pow = (prime * pow) % mod; } hash += string_hash + prime * hash; } return hash; } }; Here the rolling hash has been used. At first, we are calculating the rolling hash for the string and then the hash for the vector element.