DSA Notes
A complete guide to hash functions — the mathematical properties of a good hash function, common hashing methods (division, multiplication, universal hashing), hash functions for strings and objects, cryptographic vs non-cryptographic hashes, and Python
What a Hash Function Must Do
A hash function h: Keys → {0, 1, ..., m-1} converts any key to an integer in range [0, m-1] where m is the hash table size.
A good hash function has these properties:
- Deterministic:
h(k)always returns the same value for the same k - Uniform distribution: Each slot is equally likely for a random key
- Fast to compute: O(1) for integers, O(|key|) for strings
- Avalanche effect: Small change in key causes large change in hash (for cryptographic use)
Method 2 — Multiplication Method
def h_multiplication(key, m, A=0.6180339887): # A = (√5 - 1) / 2 (golden ratio)
return int(m * ((key * A) % 1))The fractional part of key×A is extracted, then scaled to [0, m-1].
Advantage: m does not need to be prime. Any value of m works well.
Knuth's recommendation: A = (√5 - 1) / 2 ≈ 0.6180339887 (the golden ratio conjugate) gives excellent distribution empirically.
Method 3 — Universal Hashing
Universal hashing chooses a hash function randomly from a family, making it hard for an adversary to create worst-case inputs.
Hash Functions for Strings
Polynomial Rolling Hash
The standard approach for strings. Treat the string as a polynomial:
def polynomial_hash(s, p=31, m=10**9 + 7):
"""
Polynomial rolling hash.
p=31: good for lowercase letters
p=37: good for alphanumeric
m=10^9+7: large prime prevents collisions
"""
h = 0
p_pow = 1
for char in s:
h = (h + (ord(char) - ord('a') + 1) * p_pow) % m
p_pow = (p_pow * p) % m
return h
print(polynomial_hash("abc")) # Some integer
print(polynomial_hash("bca")) # Different integer
print(polynomial_hash("abc")) # Same as first — deterministicdjb2 Hash (Fast, Popular)
def djb2(s):
h = 5381
for char in s:
h = ((h << 5) + h) + ord(char) # h = h * 33 + c
return h
# Used in: GNU C library, PostgreSQL, many programming languagesFNV Hash (Fowler-Noll-Vo)
def fnv1a(s):
"""FNV-1a hash — excellent avalanche effect, used in Go, Java."""
h = 2166136261 # FNV offset basis (32-bit)
for char in s:
h ^= ord(char)
h = (h * 16777619) % (2**32) # FNV prime
return hRabin-Karp Rolling Hash
For substring search, a rolling hash allows computing hash(s[i+1..i+k]) from hash(s[i..i+k-1]) in O(1):
Cryptographic vs Non-Cryptographic Hashes
| Feature | Non-Cryptographic | Cryptographic |
|---|---|---|
| Speed | Very fast (ns) | Slow (μs-ms) |
| Security | Not collision-resistant | Collision-resistant |
| Reversible | Sometimes | No (one-way) |
| Use case | Hash tables, checksums | Passwords, digital signatures |
| Examples | djb2, FNV, MurmurHash | SHA-256, bcrypt, SHA-3 |
# Non-cryptographic: Python's built-in hash()
print(hash("hello")) # Fast, but PREDICTABLE without randomization
# Cryptographic: hashlib
import hashlib
sha256 = hashlib.sha256("hello".encode()).hexdigest()
print(sha256) # "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
# One-way: cannot reverse to get "hello" from thisPython's hash() Behavior
# Python uses SipHash-1-3 for str, bytes, datetime (Python 3.4+)
# HASH RANDOMIZATION: hash() is different in each Python session!
print(hash("hello")) # 123456789 (different every run)
# This prevents HashDoS attacks (adversary crafting many collisions)
# Disable with PYTHONHASHSEED=0 (for reproducibility in testing)
# Numbers hash to themselves or their value:
print(hash(0) == hash(0.0) == hash(False)) # True — consistent
print(hash(1) == hash(1.0) == hash(True)) # True
# Custom objects need __hash__ and __eq__:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __hash__(self):
return hash((self.x, self.y)) # Tuple hash
def __eq__(self, other):
return self.x == other.x and self.y == other.y
p1 = Point(1, 2)
p2 = Point(1, 2)
s = {p1, p2}
print(len(s)) # 1 — p1 and p2 are equal → deduplicatedSummary
| Hash Function | Speed | Distribution | Use Case | ||
|---|---|---|---|---|---|
| Division (key % m) | O(1) | Good with prime m | Simple integers | ||
| Multiplication | O(1) | Excellent | General integers | ||
| Universal | O(1) | Provably good | Security against adversarial input | ||
| Polynomial (strings) | O( | s | ) | Excellent | Strings, substrings |
| djb2 | O( | s | ) | Good | General strings |
| FNV-1a | O( | s | ) | Excellent | Strings in Go, Java |
| SHA-256 | O( | s | ) slow | Cryptographic | Passwords, signatures |
Key insight: A perfect hash function for all cases does not exist. Choose based on key type, required security level, and performance requirements.
*Next Lesson: Collision Handling*
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Hash Functions — Design, Properties, and Common Implementations.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Data Structures & Algorithms topic.
Search Terms
data-structures-algorithms, data structures & algorithms, data, structures, algorithms, hashing, hash, functions
Related Data Structures & Algorithms Topics