Hash Table Visualization — Step by Step

Array of buckets with chaining. Hash function maps keys to bucket indices for O(1) average operations.

Data StructuresintermediateUpdated

// quick answer

Hash Table is a data structures structure that runs in O(1) time on average (O(n) worst case) with O(n) space. Array of buckets with chaining. Hash function maps keys to bucket indices for O(1) average operations.

How Hash Table Works

A Hash Table maps keys to bucket indices using a hash function (key % tableSize). Collisions are handled with chaining (linked lists per bucket). Average case O(1) for insert, search, and delete. Worst case O(n) when all keys hash to the same bucket.

Hash Table Step by Step

From key to bucket in one step

A hash table is an array of buckets plus a hash function that converts any key into a bucket index. Instead of searching for where a key lives, you *compute* it. The visualizer uses the simplest useful hash — key % tableSize — over 7 buckets: inserting 38 computes 38 % 7 = 3, so 38 goes straight into bucket 3. Looking it up later repeats the same arithmetic and lands on the same bucket immediately, no scanning. That compute-instead-of-search step is the entire trick, and it is why hash tables average O(1) for insert, search, and delete.

Collisions are inevitable

A hash function squeezes a huge key space into a handful of buckets, so sooner or later two keys must share one — a collision. With 7 buckets, the keys 10 and 24 both hash to bucket 3 (10 % 7 = 3, 24 % 7 = 3) even though they are completely different keys. Collisions are not bugs; by the pigeonhole principle they are mathematically unavoidable once you have more possible keys than buckets. What separates a good hash table from a bad one is how gracefully it handles them — and how well its hash function spreads keys so collisions stay rare.

Separate chaining, walked through

This visualizer resolves collisions with separate chaining: each bucket holds a chain — conceptually a small linked list — of every key that hashed there. Insert 10 into empty bucket 3 and the chain is [10]. Insert 24: same bucket, collision flagged, and 24 is appended, making the chain [10, 24]. Searching for 24 now takes two steps: hash to bucket 3, then walk the chain comparing 10 (no), then 24 (found). Deleting works the same way — walk the chain, unlink the match. Each operation costs one hash plus a walk of one, usually very short, chain.

Load factor and resizing

The load factor is n / buckets — average chain length. With 7 buckets and 14 keys it is 2.0, meaning searches walk about two entries; keep inserting without growing and chains lengthen until "O(1)" quietly degrades toward O(n). Real implementations pick a threshold (Java's HashMap uses 0.75), and when the load factor crosses it, they resize: allocate a larger bucket array — typically about double — and re-hash every key into it, since key % 14 lands differently than key % 7. A single resize costs O(n), but it happens so rarely that inserts remain amortized O(1).

Why lookups are O(1) — and when they are not

The average-case guarantee rests on one assumption: the hash function spreads keys roughly evenly. Then the expected chain length equals the load factor — a small constant — so a lookup is one hash plus a couple of comparisons regardless of whether the table holds a hundred entries or a hundred million. The worst case breaks that assumption: if every key lands in the same bucket, the table degenerates into one long chain and every operation costs O(n). This can happen through a poor hash function or adversarial keys — which is why production hash tables use well-mixed, often randomized (seeded) hash functions.

Time & Space Complexity

Best CaseAverage CaseWorst CaseSpace
O(1)O(1)O(n)O(n)

Hash Table Pseudocode

Hash Table operations:
  hash(key) = key % tableSize
  insert(key):
    bucket = hash(key)
    append to bucket chain
  search(key):
    bucket = hash(key)
    traverse chain until found
  delete(key):
    find in chain, remove

Press play in the visualizer above to watch each line execute with live highlighting.

Hash TableCode in JavaScript, Python & Java

JavaScript

class HashTable {
  constructor(size = 7) {
    this.size = size;
    this.buckets = Array.from({ length: size }, () => []);
  }

  hash(key) {
    return key % this.size;
  }

  insert(key) {
    this.buckets[this.hash(key)].push(key);
  }

  search(key) {
    return this.buckets[this.hash(key)].includes(key);
  }

  delete(key) {
    const bucket = this.buckets[this.hash(key)];
    const i = bucket.indexOf(key);
    if (i === -1) return false;
    bucket.splice(i, 1);
    return true;
  }
}

Python

class HashTable:
    def __init__(self, size=7):
        self.size = size
        self.buckets = [[] for _ in range(size)]

    def _hash(self, key):
        return key % self.size

    def insert(self, key):
        self.buckets[self._hash(key)].append(key)

    def search(self, key):
        return key in self.buckets[self._hash(key)]

    def delete(self, key):
        bucket = self.buckets[self._hash(key)]
        if key in bucket:
            bucket.remove(key)
            return True
        return False

Java

import java.util.ArrayList;
import java.util.List;

public class HashTable {
    private final List<List<Integer>> buckets = new ArrayList<>();
    private final int size;

    public HashTable(int size) {
        this.size = size;
        for (int i = 0; i < size; i++) {
            buckets.add(new ArrayList<>());
        }
    }

    private int hash(int key) {
        return key % size;
    }

    public void insert(int key) {
        buckets.get(hash(key)).add(key);
    }

    public boolean search(int key) {
        return buckets.get(hash(key)).contains(key);
    }

    public boolean delete(int key) {
        return buckets.get(hash(key)).remove(Integer.valueOf(key));
    }
}

When to Use Hash Table

  • Exact-key lookup is the killer feature: caches, database indexes, symbol tables in compilers, session stores, and configuration maps — any "given this key, get that value" problem.
  • Counting and grouping: frequency maps, deduplication, and set-membership tests ("have I seen this before?") all run in O(1) average per item, turning many O(n²) problems into O(n).
  • The two-pass trick behind many interview solutions (two-sum, finding duplicates, anagram grouping): trade O(n) memory for O(1) lookups instead of nested loops.
  • Not for ordered data: a hash table scatters keys deliberately, so it cannot iterate in sorted order or answer range queries ("all keys between 10 and 20") — use a binary search tree or a sorted array with binary search instead.
  • Not for min/max-first processing — a heap serves the extreme element in O(log n), which no hash table can do without scanning everything.
  • When worst-case guarantees matter (real-time systems, adversarial input), remember the O(n) degenerate case: balanced trees give a guaranteed O(log n), and for small fixed key sets a plain array can beat a hash table outright.

Hash Table — Frequently Asked Questions

Why are hash table lookups O(1)?

Because the bucket holding a key is computed, not searched for. The hash function turns the key into an array index in constant time, and array indexing is constant time. As long as keys are spread evenly and the table resizes to keep chains short, only a small constant number of entries need checking per lookup — the same amount of work whether the table holds ten entries or ten million.

What is a hash collision and how is it handled?

A collision is two different keys hashing to the same bucket index, which is unavoidable when there are more possible keys than buckets. Separate chaining handles it by letting each bucket hold a small list of entries that a lookup walks through. The alternative, open addressing, stores everything in the array itself and probes nearby slots until it finds a free one.

What is the load factor of a hash table?

The load factor is the number of stored entries divided by the number of buckets — effectively the average chain length. A load factor of 0.75 means the table is three-quarters full on average. When it crosses a threshold, the table resizes: it allocates a larger bucket array and re-hashes every existing key, keeping chains short so operations stay constant time on average.

Are JavaScript objects and Python dicts hash tables?

Yes. Python dict and set, JavaScript Map, Set, and plain objects, Java HashMap, and Go maps are all hash tables under the hood, with engineering refinements: Python uses open addressing and remembers insertion order, and Java converts long chains into balanced trees. Understanding hash tables means understanding the most heavily used data structure in nearly every modern language.

When is a hash table slow?

When many keys pile into the same bucket — from a poor hash function, adversarially chosen keys, or a table that never resizes — operations degrade from O(1) toward O(n) as lookups walk one long chain. Resizing itself causes an occasional O(n) pause. And for tasks hash tables were never built for, like sorted iteration or range queries, they lose to trees regardless of speed.

References & Further Reading