(Optional) A Faster Hash Table in C++
Author: Benjamin Qi
Prerequisites
Introduces gp_hash_table.
| Resources | |||
|---|---|---|---|
| CF | Introduces gp_hash_table | ||
| GCC | documentation | ||
| Benq (from KACTL) | |||
Read / writes are much faster than unordered_map. Its actual size is always a power of 2. The documentation is rather confusing, so I'll just summarize the most useful functions here.
1#include <ext/pb_ds/assoc_container.hpp>2using namespace __gnu_pbds;
Unordered Set
gp_hash_table<K,null_type> functions similarly to unordered_set<K>.
Hacking
gp_hash_table is also vulnerable to hacking. The hash function mentioned in the blog:
1const int RANDOM = chrono::high_resolution_clock::now().time_since_epoch().count();2struct chash {3 int operator()(int x) const { return x ^ RANDOM; }4};5gp_hash_table<key, int, chash> table;
is easily hackable (see neal's comment). To avoid this, we can replace chash with one of the custom hash functions mentioned previously.
Resizing
Unordered map has reserve. Calling this function before inserting any elements can result in a constant factor speedup.
We can modify the declaration of gp_hash_table so that it supports the resize function, which operates similarly.
1template<class K,class V> using ht = gp_hash_table<2 K,3 null_type,4 hash<K>,5 equal_to<K>,6 direct_mask_range_hashing<>,7 linear_probe_fn<>,8 hash_standard_resize_policy<9 hash_exponential_size_policy<>,10 hash_load_check_resize_trigger<>,
These are the same template arguments as the default gp_hash_table, except false has been changed to true. This modification allows us to change the actual size of the hash table.
1int main() {2 ht<int,null_type> g; g.resize(5);3 cout << g.get_actual_size() << "\n"; // 84 cout << g.size() << "\n"; // 05}
When calling g.resize(x), x is rounded up to the nearest power of 2. Then the actual size of g is changed to be equal to x (unless x < g.size(), in which case an error is thrown).
| Resources | |||
|---|---|---|---|
| GCC | documentation | ||
Furthermore, if we construct g with the following arguments:
1ht<int,null_type> g({},{},{},{},{1<<16});
then the actual size of g is always at least 1<<16 (regardless of calls to resize). The last argument must be a power of 2 (or else errors will be thrown).
Solving 3SUM
Focus Problem – read through this problem before continuing!
Since all the values are quite small, you can use an array instead of a hashmap. But if you didn't read the constraints carefully enough, you're in luck!
Solution
Problems
Module Progress:
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!