DSA Tutorial menu

DSA Hash Tables

A hash table stores key and value pairs and finds any key almost instantly.

The Idea

Imagine a school with 26 cupboards, one for each letter. Ayesha's file goes in cupboard A, Bilal's in cupboard B. To find Bilal's file you go straight to B instead of searching every cupboard.

A hash table does the same with a hash function: it turns a key into a number, and that number decides the bucket where the value is stored.

A Tiny Hash Function

Here is a simple (not very good) hash function that adds the character codes and takes the remainder:

Example

python
def simple_hash(key, size):
    total = 0
    for ch in key:
        total += ord(ch)
    return total % size

for name in ["Ali", "Sara", "Hamza"]:
    print(name, "->", simple_hash(name, 10))
Output
Ali -> 8
Sara -> 1
Hamza -> 7

So "Ali" would be stored in bucket 8 of a table with 10 buckets.

Collisions

Sometimes two keys get the same bucket. This is a collision. A common fix is chaining: each bucket holds a small list of pairs.

Example

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

    def _index(self, key):
        return sum(ord(c) for c in key) % len(self.buckets)

    def put(self, key, value):
        bucket = self.buckets[self._index(key)]
        for pair in bucket:
            if pair[0] == key:
                pair[1] = value
                return
        bucket.append([key, value])

    def get(self, key):
        for k, v in self.buckets[self._index(key)]:
            if k == key:
                return v
        return None

prices = HashTable()
prices.put("chai", 60)
prices.put("samosa", 40)
prices.put("chai", 70)
print(prices.get("chai"))
print(prices.get("samosa"))
print(prices.get("pizza"))
Output
70
40
None

Costs

OperationAverageWorst case
InsertO(1)O(n)
Look upO(1)O(n)
DeleteO(1)O(n)

The worst case only happens if almost every key lands in the same bucket. Good hash functions spread keys evenly, so real hash tables are very fast.

Python's dict and set are hash tables built for you, with an excellent hash function. In real code, use them instead of writing your own.

Using a Dictionary to Count

Counting how often each item appears is a classic hash table job:

Example

python
words = "chai biryani chai nihari chai biryani".split()

counts = {}
for w in words:
    counts[w] = counts.get(w, 0) + 1

print(counts)
print(max(counts, key=counts.get))
Output
{'chai': 3, 'biryani': 2, 'nihari': 1}
chai

This is O(n). Doing the same with nested loops would be O(n^2).

Using a Set for Fast Checks

The two-sum problem: does any pair of numbers add up to a target? A set makes it O(n).

Example

python
def two_sum(numbers, target):
    seen = set()
    for n in numbers:
        if target - n in seen:
            return (target - n, n)
        seen.add(n)
    return None

print(two_sum([8, 3, 11, 5, 7], 12))
print(two_sum([1, 2, 3], 50))
Output
(5, 7)
None

For each number we ask, "have I already seen the number that completes the pair?" Checking a set takes O(1) on average.

Exercise

Exercise

What is a collision in a hash table?

Learn DSA with a teacher

Join the Python Programming course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp