What does the simple uniform hashing assumption claim, and when do real keys violate it?
answer
- an assumption, not an observation
- equally likely, and independent, of what
- who provides the uniformity: keys or function
- expected chain length equals the load factor
- structured keys plus weak mixing means clustering
basics
~20 sSimple uniform hashing assumes each key is equally likely to land in any bucket, independently. That uniformity comes from the hash function, not from the data: a weak mixer that discards the bits where keys differ clusters them and kills the expected bound.
solid answer
~50 sThe assumption is that every key is equally likely to map to any of the `m` buckets, independently — which is what makes the expected chain length equal the load factor `n/m` and gives lookup its `Theta(1 + alpha)` expected cost. The nuance is *who supplies* that uniformity: not your data, but the composition of your key set with the hash function and the step that turns a hash value into a bucket index. A strong mixing function scatters even highly structured keys. It breaks when the hash barely mixes — say the index is taken from the low bits of a value whose keys vary only in the high bits, so thousands of distinct keys collide on one bucket. That is a real-world failure with no adversary involved: the keys were structured and the mixing was too weak to hide it.
go deeper
Know that the constant-time claim rests on keys spreading evenly across buckets, and that this spreading is produced by the hash function rather than assumed about the data.
Explain the assumption in its exact form — equally likely, independent — and derive the expected chain length from it. Then name a concrete way the index derivation can discard the very bits that distinguish your keys.
Demonstrate diagnosis: measure the bucket-occupancy distribution against what the model predicts, and separate a genuine clustering defect from ordinary variance or from a merely hot key.
Frame this as a review standard for key design. When a team picks a key format and a table size together, someone should be asking which bits carry the entropy and whether the indexing step keeps them.
## The assumption, stated exactly Simple uniform hashing (SUHA) is the modelling assumption behind essentially every hash-table cost claim you will be asked to state. It says: for a table with `m` buckets, each key that gets stored is equally likely to hash to any one of the `m` buckets, and keys' bucket choices are independent of each other. It is an assumption about a *probability model*, not a claim you can verify by looking at a table. From it the standard results follow. With separate chaining and `n` entries, the expected number of entries in the bucket you probe is the load factor `alpha = n/m`, so an unsuccessful search costs `Theta(1 + alpha)` expected and a successful one the same order. Keep `alpha` bounded by a growth policy and both are expected O(1). Under the same assumption, when `n` keys go into `n` buckets the *longest* chain is not constant — it is `Theta(log n / log log n)` in expectation. Even the ideal model produces buckets several times the average, which is a useful thing to know before you go looking for a bug. ## Who supplies the uniformity The most common misreading is that SUHA is a hope about your data — that it holds if your keys "look random" and fails if they look structured. That is backwards in practice. Real keys are almost never uniform: region codes share prefixes, identifiers are sequential, timestamps are dense, paths repeat directory segments. The job of a hash function is to destroy that structure. A function with good avalanche behaviour — where flipping one input bit changes about half the output bits — maps a structured key set to output values that behave, for indexing purposes, like uniform ones. So the assumption is a property of the *pair* (key set, hash-and-index pipeline), and the pipeline is the part you control. ## How it actually fails Three realistic failure shapes, none of which needs an attacker: 1. **The index derivation throws away the mixed bits.** Tables sized as a power of two typically take the index from the low bits of the hash. If the hash function preserves input structure in the high bits and the keys differ mainly there, all that entropy is masked off. This is why implementations add a finalisation step that folds high bits down into low ones before masking, and why prime-sized tables using a modulus are more forgiving of a mediocre hash. 2. **The hash ignores part of the key.** A hash that samples only a prefix or only a bounded number of characters will collide every key sharing that prefix — a genuine hazard for keys like hierarchical region or postal codes, where a five-character code's first two characters name the region and thousands of codes share them. 3. **A cheap, near-identity hash on numeric keys.** Using the raw numeric value as the hash is fine when values are dense and the table is prime-sized, and terrible when the values are multiples of a stride that shares a factor with the table size, which lands them all on a fraction of the buckets. Mainstream runtimes hedge this differently for the same reason: Java's hash map folds a value's high bits into its low bits before masking, while Python's dict leaves the value alone and instead perturbs the probe sequence with the unmasked bits, so displaced keys stop marching in lockstep. Two routes, one goal — make the index depend on the whole hash. ## The distinction candidates miss: frequency is not collision If a table keyed by region code receives a million records for the same dense metro code, that is **not** a collision problem. A map stores one entry per distinct key; the millionth insert of the same key overwrites or updates the entry it already has. Neither the entry count, the load factor, nor any chain grows. Skewed *access* frequency is a cache and contention story, not a hashing one. What matters for SUHA is how the **distinct** keys distribute — so the question to ask about the region-code table is how many distinct codes exist and whether the pipeline scatters them, not how popular any one of them is. ## What to do about it Diagnose by measuring, not by guessing: sample the bucket-occupancy distribution and compare it with the model. Under SUHA at `alpha` near one, most buckets hold zero to a few entries and the maximum sits near `log n / log log n`. A distribution with a handful of buckets holding orders of magnitude more, and vast empty stretches, points at the hash or at the index derivation — not at bad luck. The fixes are of a piece: mix the whole key, fold the high bits into the index, and choose a table size that does not collude with the keys' stride.
- A table keyed by region code receives a million records for one dense metro code. Does that violate uniform hashing?No. A map holds one entry per distinct key, so repeated inserts of the same code update a single entry — the entry count, the load factor and every chain stay exactly as they were. Uniform hashing is about how the *distinct* keys spread across buckets. Repeated access to one hot key is a cache-locality and contention question, not a collision one.
- How would you check whether a live table's keys are actually spreading?Sample the bucket-occupancy distribution rather than an average. Under uniform hashing with a load factor near one, most buckets hold zero to a few entries and the longest chain sits around log n / log log n. Seeing a few buckets orders of magnitude above that, with large empty stretches, points at the hash function or at the step that derives an index from it.
- Two keys have completely different hash values. Can they still collide?Yes, and this is the step people forget. The bucket index is derived from the hash — typically by masking low bits for a power-of-two table or taking a modulus for a prime-sized one — so any two hash values congruent under that reduction land together. Distinct hashes only avoid collisions if the reduction preserves the bits in which they differ.
saying these in an interview costs you the question
- Uniform hashing is a property of the input data alone
- Structured keys always cluster no matter the hash function
- Repeated inserts of one hot key create collisions
- Distinct hash values guarantee distinct buckets
- If the average chain is short, no bucket is long