In separate chaining, what happens when two keys hash to the same bucket, and what does a lookup then cost?
answer
- One bucket, more than one entry
- Nothing is overwritten, something is linked
- The hash picks the bucket only
- Cost is one index plus a walk
- Equal hashes do not mean equal keys
basics
~20 sBoth keys stay: the bucket holds a list, and the new entry is linked into that list. A lookup indexes the bucket in constant time, then walks the chain comparing full keys, so its cost grows with the chain's length.
solid answer
~40 sIn separate chaining every bucket holds a container of entries — classically a singly linked list — instead of one entry. A collision is therefore not an error and not an overwrite: the second key is linked into the same bucket's chain and both remain findable. A lookup does two things: compute the hash and index the bucket, which is constant time, then walk that bucket's chain comparing the **full key** of each node, because equal hash values do not mean equal keys. So the real cost is `1 + (nodes walked)`. With a well-spread hash and a bounded load factor the chain is short and lookups are constant time *in expectation*, but the walk is the part that can grow — that is why chaining's guarantee is expected, not absolute.
code
pseudocode · 7 linesb = hash(key) mod length(table)
node = table[b]
while node != null:
if node.key == key:
return node.value
node = node.next
return NOT_FOUNDgo deeper
Recall that a bucket holds a list, not one entry, and that both colliding keys survive. Be ready to say the lookup indexes the bucket in constant time and then walks the chain comparing keys.
Explain the mechanics: head insertion is O(1) but map semantics force a scan first, deletion is a simple unlink, and a cached hash is only a filter ahead of the real key comparison.
Show where the cost actually goes in production: the bucket index is free, the chain walk is not, and a hash that spreads badly turns a healthy table into a slow one without any error being raised.
Own the framing that chaining buys correctness under collisions but only an expected-time guarantee. Be ready to say what your service does when that expectation fails and who is watching for it.
## The problem chaining solves A hash table maps a key to a slot by reducing the key's hash value into the range of a bucket array. Because there are far more possible keys than buckets, two distinct keys will eventually reduce to the same index. That is not bad luck; the pigeonhole principle guarantees it. Every hash table therefore needs a collision-resolution strategy, and separate chaining is the most direct one: **make each bucket hold a collection of entries rather than a single entry.** ## What a bucket actually holds In the classic form, each bucket holds a pointer to the head of a singly linked list. Each list node stores the key, its value, and a pointer to the next node — many implementations also cache the entry's hash value in the node, which pays off later. The bucket array itself is just an array of pointers, most of which may be null. Consider a log-ingestion service that maps a session identifier to the list of events seen for that session. Two different session identifiers can easily land in bucket 7. Chaining's answer is that bucket 7 now holds a two-node chain, and both sessions are retrievable. ## The three operations **Lookup.** Compute the hash, reduce it to a bucket index, then walk that bucket's chain. For each node, compare the stored key with the search key for *equality*. If a cached hash is stored in the node, compare hashes first as a cheap filter and fall back to full key comparison only when they match — a hash mismatch proves the keys differ, but a hash match proves nothing. Cost: one constant-time index plus one comparison per node walked. **Insert.** Compute the bucket, then link the new node in. Linking at the head is O(1) and needs no traversal. But if the table has map semantics — one value per key, where re-inserting an existing key must replace rather than duplicate — the insert must first scan the chain to find an existing entry. Skipping that scan is a classic bug: the table silently accumulates two nodes with the same key, and lookups return whichever the walk reaches first, so the older entry is shadowed but never freed. **Delete.** Walk the chain, unlink the node, done. Nothing about the rest of the table is disturbed, and no marker has to be left behind — a genuine simplicity advantage of chaining over strategies that store entries directly in the bucket array. ## Why the collision is not an overwrite The single most common junior error is to say the second key overwrites the first, or that a collision forces an immediate resize. Neither is true. Overwriting happens only when the *keys are equal*, which is decided by the equality comparison, not by the hash. And a resize is triggered by the table's overall load factor crossing a threshold, not by any individual collision — a table can and does operate with collisions present at all times. ## What the cost really is Describe the cost as "constant time plus the chain walk" and you will always be right. The bucket index is O(1). The walk is proportional to the number of entries in that one bucket. When keys spread evenly and the table resizes to keep the ratio of entries to buckets bounded, chains stay short and lookups are O(1) *expected*. When keys spread badly, one chain can hold a large share of the entries and lookups on it degrade toward O(n) — the table still returns correct answers, it just gets slow. This is why careful people say hash lookups are O(1) expected and O(n) worst case, never "O(1), full stop". ## Interview framing If you are asked "what happens on a collision", answer in three beats: both entries are kept in the same bucket's chain; lookup indexes the bucket then scans the chain comparing full keys; the cost is therefore one plus the chain length, which is short only when the hash distributes well. That answer shows you know the mechanism *and* where its guarantee comes from, which is exactly the difference the interviewer is listening for.
- If a node already caches its entry's hash value, why still compare the full key?Because equal hash values do not prove equal keys — two distinct keys can share a hash value entirely, not just a bucket. The cached hash is a cheap filter: a mismatch lets you skip the expensive key comparison, which matters when keys are long strings or composite objects. Only an equality check on the key itself can confirm a match.
- Inserting at the head of a chain is O(1). When is that unsafe?When the table has map semantics, where re-inserting an existing key must replace the old value. Head insertion without first scanning the chain creates a second node with the same key; lookups then find whichever node the walk reaches first and the other is shadowed forever. Set and map tables must scan before linking; a multimap that intentionally allows duplicates need not.
- Does a collision force the table to resize?No. Resizing is driven by the table's overall load factor — entries divided by buckets — crossing a threshold, not by any single collision. A healthy chained table has collisions at all times and simply keeps its chains short. Resizing on every collision would rehash constantly and buy nothing.
A bucket is a peg on a coat rack, not a single hook. Several coats can hang on one peg, and finding yours means looking through the coats already hanging there.
saying these in an interview costs you the question
- Says the second key overwrites the first
- Says a collision means the table is broken
- Claims chained lookups are O(1) regardless of chain length
- Treats equal hash values as proof of equal keys
- Thinks every collision triggers an immediate resize