Collision Handling Using Chaining in DSA Go - Time & Space Complexity
When we use chaining to handle collisions in a hash table, we want to know how fast operations like insert or search run as the table grows.
We ask: How does the time to find or add an item change when more items are stored?
Analyze the time complexity of the following code snippet.
func (ht *HashTable) Search(key string) *Node {
index := ht.hash(key)
current := ht.buckets[index]
for current != nil {
if current.key == key {
return current
}
current = current.next
}
return nil
}
This code searches for a key in a hash table using chaining, by traversing the linked list at the hashed bucket.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Traversing the linked list at the bucket to find the key.
- How many times: Up to the number of elements stored in that bucket's chain.
As more items are added, chains may get longer, making searches slower.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 1 to 2 steps per search |
| 100 | About 10 steps if chains grow |
| 1000 | About 100 steps if chains are long |
Pattern observation: If the number of buckets stays fixed, operations grow roughly linearly with n because chains get longer.
Time Complexity: O(n)
This means in the worst case, searching can take time proportional to the number of items stored, if many keys collide into the same bucket.
[X] Wrong: "Hash table search is always O(1) no matter what."
[OK] Correct: If many keys collide, the linked list grows, making search slower and closer to O(n).
Understanding how chaining affects time helps you explain hash table behavior clearly and shows you know real-world trade-offs.
"What if we resize the hash table and rehash keys when load grows? How would the time complexity change?"
Practice
collision handling using chaining in hash tables?Solution
Step 1: Understand collision in hash tables
When two keys hash to the same index, a collision happens.Step 2: How chaining handles collisions
Chaining stores all collided elements in a linked list at that index.Final Answer:
Store multiple elements in a linked list at the same index when collisions occur -> Option CQuick Check:
Chaining = linked list at index [OK]
- Thinking chaining resizes the table
- Confusing chaining with open addressing
- Assuming collisions are ignored
Solution
Step 1: Understand Go slice declaration for chaining
Chaining uses a slice of pointers to linked list nodes for dynamic size.Step 2: Identify correct syntax
Using make([]*Node, 10) creates a slice of 10 pointers to Node, suitable for chaining.Final Answer:
var table = make([]*Node, 10) -> Option BQuick Check:
Slice of pointers = make([]*Node, size) [OK]
- Using arrays instead of slices limits flexibility
- Using map instead of slice for chaining
- Declaring slice without make causes nil slice
key % 10?
type Node struct {
key int
next *Node
}
func insert(table []*Node, key int) {
index := key % 10
newNode := &Node{key: key}
newNode.next = table[index]
table[index] = newNode
}
func printTable(table []*Node) {
for i, node := range table {
print(i, ": ")
for n := node; n != nil; n = n.next {
print(n.key, " -> ")
}
println("nil")
}
}
func main() {
table := make([]*Node, 10)
insert(table, 5)
insert(table, 15)
printTable(table)
}Solution
Step 1: Calculate hash index for keys 5 and 15
Both 5 % 10 and 15 % 10 equal 5, so both keys go to index 5.Step 2: Trace insertion order in chaining
First insert 5 at index 5, then insert 15 which becomes new head pointing to 5.Final Answer:
15 -> 5 -> nil at index 5 -> Option AQuick Check:
New nodes added at head = 15 first [OK]
- Assuming insertion appends at tail
- Mixing up hash index calculation
- Printing nodes in wrong order
type Node struct {
key int
next *Node
}
func insert(table []*Node, key int) {
index := key % len(table)
if table[index] == nil {
table[index].key = key
} else {
newNode := &Node{key: key, next: table[index]}
table[index] = newNode
}
}
func main() {
table := make([]*Node, 10)
insert(table, 7)
}Solution
Step 1: Analyze the nil check and assignment
If table[index] is nil, trying to assign table[index].key causes nil pointer dereference.Step 2: Understand pointer initialization requirement
Must create a new Node and assign pointer to table[index] before setting key.Final Answer:
Nil pointer dereference when assigning to table[index].key -> Option AQuick Check:
Assigning field on nil pointer causes panic [OK]
- Ignoring nil pointer before field assignment
- Assuming slice elements auto-initialize
- Confusing compile error with runtime panic
Solution
Step 1: Understand deletion in chaining
To delete a key, find it in the linked list and remove its node by adjusting pointers.Step 2: Why other options fail
Setting entire list to nil removes all keys, replacing key with zero keeps node, resizing is inefficient.Final Answer:
Traverse the linked list at the index, keep track of previous node, and adjust pointers to skip the node with the key -> Option DQuick Check:
Proper deletion adjusts pointers in linked list [OK]
- Removing entire chain instead of one key
- Leaving empty nodes with zero keys
- Rehashing unnecessarily on deletion
Ready to prove it?
Pass the test and this pattern moves unknown
