Hash-Based Design: Building Smart Storage Systems đď¸
Imagine you have a magical library where books can teleport to your hands instantly. Thatâs what weâre building today!
The Story: The Library of Instant Answers
Once upon a time, there was a tiny village with a HUGE library. People would ask for books all day long. But the librarian had a problemâshe couldnât remember where every book was!
So she invented three magical tools:
- A Magic Bookshelf (HashMap) - stores books with instant lookup
- A Guest Book (HashSet) - remembers who visited, no duplicates
- A âRecently Popularâ Display (LRU Cache) - shows the books people asked for most recently
Letâs learn how to build each one!
1. Design HashMap: Your Magic Bookshelf đ
What Is a HashMap?
Think of it like a coat check at a party:
- You give them your coat (the value)
- They give you a ticket number (the key)
- Later, you show your ticket and get your coat INSTANTLY!
# Simple HashMap Example
my_map = {}
my_map["apple"] = 5 # Store: key="apple", value=5
print(my_map["apple"]) # Get: returns 5 instantly!
How Does the Magic Work?
The secret is a hash functionâit turns any key into a number (an index).
graph TD A["Key: 'apple'"] --> B["Hash Function"] B --> C["Index: 3"] C --> D["Store at position 3"]
Building Your Own HashMap
Hereâs the recipe:
class MyHashMap:
def __init__(self):
# Create 1000 empty buckets
self.size = 1000
self.buckets = [[] for _ in range(self.size)]
def _hash(self, key):
# Turn key into bucket number
return key % self.size
def put(self, key, value):
# Find the right bucket
idx = self._hash(key)
# Check if key exists, update it
for i, (k, v) in enumerate(self.buckets[idx]):
if k == key:
self.buckets[idx][i] = (key, value)
return
# New key, add it
self.buckets[idx].append((key, value))
def get(self, key):
idx = self._hash(key)
for k, v in self.buckets[idx]:
if k == key:
return v
return -1 # Not found
def remove(self, key):
idx = self._hash(key)
for i, (k, v) in enumerate(self.buckets[idx]):
if k == key:
del self.buckets[idx][i]
return
Why Buckets?
Sometimes two keys get the same hash (called a collision).
Example: Both âcatâ and âactâ might hash to index 7!
We solve this by making each position a list (bucket) that can hold multiple items.
Index 0: []
Index 1: [("dog", 10)]
Index 2: []
Index 3: [("cat", 5), ("act", 3)] â Both live here!
2. Design HashSet: The Guest Book đ
What Is a HashSet?
Itâs like a VIP list at a club:
- You can add a name
- You can check if someoneâs on the list
- You can remove a name
- No duplicates allowed! (Canât add the same person twice)
HashSet vs HashMap
| HashMap | HashSet |
|---|---|
| Stores key-value pairs | Stores just keys |
{"apple": 5} |
{"apple"} |
| Dictionary | Unique collection |
Building Your Own HashSet
class MyHashSet:
def __init__(self):
self.size = 1000
self.buckets = [[] for _ in range(self.size)]
def _hash(self, key):
return key % self.size
def add(self, key):
idx = self._hash(key)
# Only add if not already there
if key not in self.buckets[idx]:
self.buckets[idx].append(key)
def contains(self, key):
idx = self._hash(key)
return key in self.buckets[idx]
def remove(self, key):
idx = self._hash(key)
if key in self.buckets[idx]:
self.buckets[idx].remove(key)
Real-World Uses
- Checking if a username is taken
- Tracking which pages youâve visited
- Finding unique words in a document
3. LRU Cache: The âRecently Popularâ Display đ
What Is LRU Cache?
LRU = Least Recently Used
Imagine your desk can only hold 3 books. When you want a 4th book, you must remove one. Which one? The one you havenât touched in the longest time!
graph TD A["Desk has: Book A, B, C"] --> B["Want Book D"] B --> C["Remove A #40;oldest#41;"] C --> D["Desk now: B, C, D"]
Why Do We Need This?
Your computer has limited fast memory. LRU Cache keeps the most useful stuff ready and throws away what you havenât used.
Real examples:
- Browser history (recent pages load faster)
- Netflix (recently watched shows are ready)
- Your phoneâs app switcher
The Secret Recipe
We need TWO ingredients:
- HashMap - for instant lookup (O(1) access)
- Doubly Linked List - to track order of use
graph LR subgraph "Order #40;Most â Least Recent#41;" HEAD --> D --> C --> B --> TAIL end subgraph "HashMap" KEY_D --> D KEY_C --> C KEY_B --> B end
Building Your Own LRU Cache
class Node:
def __init__(self, key=0, val=0):
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity):
self.capacity = capacity
self.cache = {} # HashMap: key â Node
# Dummy head and tail
self.head = Node()
self.tail = Node()
self.head.next = self.tail
self.tail.prev = self.head
def _remove(self, node):
# Remove node from list
node.prev.next = node.next
node.next.prev = node.prev
def _add_to_front(self, node):
# Add right after head
node.next = self.head.next
node.prev = self.head
self.head.next.prev = node
self.head.next = node
def get(self, key):
if key not in self.cache:
return -1
node = self.cache[key]
# Move to front (most recent)
self._remove(node)
self._add_to_front(node)
return node.val
def put(self, key, value):
if key in self.cache:
# Update existing
self._remove(self.cache[key])
node = Node(key, value)
self.cache[key] = node
self._add_to_front(node)
if len(self.cache) > self.capacity:
# Remove least recent (before tail)
lru = self.tail.prev
self._remove(lru)
del self.cache[lru.key]
Letâs Walk Through an Example!
LRU Cache with capacity = 2
| Action | Cache State | What Happened |
|---|---|---|
put(1, 1) |
[1] |
Added key 1 |
put(2, 2) |
[2, 1] |
Added key 2 (front) |
get(1) |
[1, 2] |
Accessed 1, moved to front |
put(3, 3) |
[3, 1] |
Added 3, removed 2 (LRU) |
get(2) |
[3, 1] |
Returns -1, key 2 was removed! |
The Big Picture: How They Connect
graph TD subgraph "Hash-Based Structures" A["HashMap"] --> |"Stores keyâvalue"| D["Instant Lookup O#40;1#41;"] B["HashSet"] --> |"Stores unique keys"| D C["LRU Cache"] --> |"HashMap + Linked List"| D end C --> E["Limited Capacity"] C --> F["Removes Least Used"]
Summary: Your New Superpowers! đڏ
| Structure | What It Does | When to Use It |
|---|---|---|
| HashMap | Stores pairs, instant lookup | Phone contacts, word count |
| HashSet | Stores unique items only | Check duplicates, visited pages |
| LRU Cache | Smart storage with limit | Browser cache, recent files |
Time Complexity Cheat Code
| Operation | HashMap | HashSet | LRU Cache |
|---|---|---|---|
| Add/Put | O(1) | O(1) | O(1) |
| Get | O(1) | - | O(1) |
| Remove | O(1) | O(1) | O(1) |
| Contains | O(1) | O(1) | O(1) |
You Did It! đ
You now understand three powerful tools that real engineers use every day:
- HashMap - Your instant-access dictionary
- HashSet - Your no-duplicates list
- LRU Cache - Your smart, limited-space storage
These are the building blocks of:
- Databases
- Web browsers
- Operating systems
- Every app on your phone!
Next time you search for something and it appears instantlyâyouâll know a HashMap helped make that happen!
âThe best data structure is the one that makes the impossible feel instant.â
