Skip to content
Part IA Lent Term

Hash Functions

Definition and Role

A hash function h:U{0,1,,m1}h: U \to \{0, 1, \ldots, m-1\} maps keys from the universe UU to mm slots in a hash table. A good hash function satisfies:

  1. Fast to compute: Θ(1)\Theta(1) time per call. If the hash function itself is slow, the O(1)O(1) promise of hash tables is hollow (hidden large constant factors).
  2. Uniform distribution: each of the mm slots is equally likely for a random key. This is the simple uniform hashing assumption, which makes expected-case analysis possible.
  3. 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:

h(s)=(i=0s1s[i]Bs1i)modmh(s) = \left( \sum_{i=0}^{|s|-1} s[i] \cdot B^{|s|-1-i} \right) \bmod m

The choice of base BB and modulus mm affects distribution quality.

Division Method

h(k)=kmodmh(k) = k \bmod m

This is fast (one modular division), but the choice of mm is critical:

  • Avoid powers of 2 (e.g. m=2pm = 2^p): then h(k)h(k) depends only on the lowest pp bits of kk, ignoring higher-order bits. This produces poor distribution if keys share low-bit patterns.
  • Prefer mm as a prime number not too close to a power of 2. A prime modulus ensures all bits of kk influence the hash value.

Example: For m=10m = 10, h(23)=3h(23) = 3, h(47)=7h(47) = 7, h(13)=3h(13) = 3 (collision). For m=11m = 11 (prime): h(23)=1h(23) = 1, h(47)=3h(47) = 3, h(13)=2h(13) = 2 (no collision).

Multiplication Method

h(k)=m(kAmod1)h(k) = \lfloor m (kA \bmod 1) \rfloor

where AA is a constant in (0,1)(0, 1). Knuth recommends A(51)/20.6180339887A \approx (\sqrt{5} - 1)/2 \approx 0.6180339887 (the golden ratio conjugate).

The idea: multiply kk by AA, extract the fractional part (kAmod1)(kA \bmod 1), and scale by mm. The fractional part distributes keys uniformly across [0,1)[0, 1) regardless of patterns in kk. The method works for any mm, 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:

index=hraw(k)modm\text{index} = h_{\text{raw}}(k) \bmod m

This is fast but introduces slight bias unless mm 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

MethodFormulaProsCons
Divisionkmodmk \bmod mSimple, fastNeed prime mm
Multiplicationm(kAmod1)\lfloor m(kA \bmod 1) \rfloorWorks for any mmSlightly slower
Range reductionhraw(k)modmh_{\text{raw}}(k) \bmod mDecouples hash from table sizeMinor bias
Polynomial (strings)s[i]Bimodm\sum s[i] \cdot B^i \bmod mGood for stringsParameter-sensitive
Desired propertyUniform distribution over [0,m1][0, m-1]