Hash Functions
Definition and Role
A hash function maps keys from the universe to slots in a hash table. A good hash function satisfies:
- Fast to compute: time per call. If the hash function itself is slow, the promise of hash tables is hollow (hidden large constant factors).
- Uniform distribution: each of the slots is equally likely for a random key. This is the simple uniform hashing assumption, which makes expected-case analysis possible.
- Deterministic: the same key always maps to the same slot (unless using universal hashing where the function is chosen at random at runtime).
Handling Non-Integer Keys
Hash functions ultimately produce integers. For non-integer keys (strings, objects), the key must first be converted to an integer. A common approach for strings: treat each character as a digit in a large base (e.g. 256 for ASCII), producing a polynomial:
The choice of base and modulus affects distribution quality.
Division Method
This is fast (one modular division), but the choice of is critical:
- Avoid powers of 2 (e.g. ): then depends only on the lowest bits of , ignoring higher-order bits. This produces poor distribution if keys share low-bit patterns.
- Prefer as a prime number not too close to a power of 2. A prime modulus ensures all bits of influence the hash value.
Example: For , , , (collision). For (prime): , , (no collision).
Multiplication Method
where is a constant in . Knuth recommends (the golden ratio conjugate).
The idea: multiply by , extract the fractional part , and scale by . The fractional part distributes keys uniformly across regardless of patterns in . The method works for any , which is convenient when resizing tables.
Range Reduction
Modern hash functions typically output a 32-bit or 64-bit unsigned integer (e.g. 0..2^32-1). This raw output is too large to use as a table index. Range reduction converts it:
This is fast but introduces slight bias unless divides the hash output range. In practice, the bias is negligible for well-designed hash functions.
Cryptographic vs Non-Cryptographic Hashing
Cryptographic hash functions (SHA-256, BLAKE3) provide strong guarantees: collision resistance, preimage resistance. They are slow by design and not needed for hash tables.
Non-cryptographic hash functions (MurmurHash, FNV-1a, xxHash) prioritise speed and reasonable distribution. These are the appropriate choice for in-memory data structures. The Cambridge course focuses on the latter.
Low-Entropy Inputs
If keys have low entropy (e.g. single letters, or words differing by one character like ROT, TOT, POT), even a good hash function cannot produce a uniform distribution: there are only 26 possible inputs, so at most 26 distinct hash values. For such inputs, choose domain-specific hash functions that maximise spread.
Summary
| Method | Formula | Pros | Cons |
|---|---|---|---|
| Division | Simple, fast | Need prime | |
| Multiplication | Works for any | Slightly slower | |
| Range reduction | Decouples hash from table size | Minor bias | |
| Polynomial (strings) | Good for strings | Parameter-sensitive | |
| Desired property | Uniform distribution over |