software-engineer-blog logoSoftware Engineer Blog

Module 3 · Complexity and data structures

Unit 11 of 49

Unit 11 · Module 3 · Complexity and data structures

Hash tables — the one to truly understand

Average O(1), until it is not. Collisions, load factor, and what a dict really is.

Unit 11 of the free 49-unit computer-science course, in complexity and data structures. 1 topic to watch or read, 4 interview questions answered in full and a short self-check.

Watch or read

One topic makes up this unit. Take each one whichever way suits you, then answer the questions below.

Hash tables explained in detail

You use a hash table every day and almost nobody can say what happens underneath. Built from scratch in about twenty lines of Python: the hash function, the bucket index, a real collision, chaining, the load factor, the resize — and where O(1) quietly stops being true.

Read

Interview questions this unit unlocks

Asked out loud, answered out loud. Read the answer, then say it in your own words.

How does a hash table give you O(1) lookup?

The key is hashed to an integer, that integer is reduced modulo the number of buckets, and the entry lives in that bucket — so finding it is arithmetic, not searching. The O(1) is average case and it depends on the hash spreading keys evenly. If every key lands in one bucket you have written a linked list with extra steps, and lookup degrades to O(n).

That degradation is a real attack: hash-flooding sends crafted keys that all collide. It is why runtimes seed their hash functions randomly per process.

What happens on a collision?

Two strategies. Chaining keeps a list (or a small tree) per bucket and appends — simple, tolerant of a high load factor, and it costs a pointer chase. Open addressing probes for the next free slot in the same array — no pointers, cache-friendly, but it degrades sharply as the table fills and deletion needs tombstones so a probe sequence is not broken.

What is the load factor, and what happens when it is exceeded?

Entries divided by buckets. Once it crosses a threshold — around 0.75 for chaining, lower for open addressing — collisions stop being rare and lookups start walking. The table then resizes: it allocates roughly double the buckets and rehashes every key, because the bucket index depends on the bucket count. That single operation is O(n), which is why insertion into a hash table is amortised O(1) rather than plain O(1).

If you know the size in advance, pre-sizing the map skips every intermediate rehash. It is one of the cheapest wins in a hot loop.

What makes a good hash function here?

Fast, deterministic within a process, and it must avalanche — flipping one bit of the key should change about half the bits of the output, so near-identical keys do not land in neighbouring buckets. It does not need to be cryptographic; a hash table is not a security primitive, and using SHA-256 as a dictionary hash buys nothing but latency.

Self-check — 5 questions

Answer alone, at 2am, with no interviewer in the room.

Part of Everything You Need to Know About Computer Science.