Consider a simple HashMap implemented with separate chaining. After inserting keys and values, what will be the output of the get operation?
var map = new SimpleHashMap(); map.Put("apple", 10); map.Put("banana", 20); map.Put("apple", 30); var result = map.Get("apple"); Console.WriteLine(result); class SimpleHashMap { private readonly int size = 5; private LinkedList<KeyValuePair<string, int>>[] buckets; public SimpleHashMap() { buckets = new LinkedList<KeyValuePair<string, int>>[size]; for (int i = 0; i < size; i++) buckets[i] = new LinkedList<KeyValuePair<string, int>>(); } private int GetBucketIndex(string key) { return Math.Abs(key.GetHashCode()) % size; } public void Put(string key, int value) { int index = GetBucketIndex(key); var bucket = buckets[index]; foreach (var pair in bucket) { if (pair.Key == key) { bucket.Remove(pair); break; } } bucket.AddLast(new KeyValuePair<string, int>(key, value)); } public int Get(string key) { int index = GetBucketIndex(key); var bucket = buckets[index]; foreach (var pair in bucket) { if (pair.Key == key) return pair.Value; } return -1; // Not found } }
When inserting a key that already exists, the old value is replaced.
The key "apple" is first inserted with value 10, then updated to 30. The get returns the latest value 30.
Given the following sequence of put and remove operations on a HashMap, what is the final number of key-value pairs stored?
var map = new SimpleHashMap(); map.Put("cat", 1); map.Put("dog", 2); map.Put("bird", 3); map.Remove("dog"); map.Put("cat", 4); map.Put("fish", 5); int size = map.Size(); Console.WriteLine(size); class SimpleHashMap { private readonly int size = 5; private LinkedList<KeyValuePair<string, int>>[] buckets; public SimpleHashMap() { buckets = new LinkedList<KeyValuePair<string, int>>[size]; for (int i = 0; i < size; i++) buckets[i] = new LinkedList<KeyValuePair<string, int>>(); } private int GetBucketIndex(string key) { return Math.Abs(key.GetHashCode()) % size; } public void Put(string key, int value) { int index = GetBucketIndex(key); var bucket = buckets[index]; foreach (var pair in bucket) { if (pair.Key == key) { bucket.Remove(pair); break; } } bucket.AddLast(new KeyValuePair<string, int>(key, value)); } public void Remove(string key) { int index = GetBucketIndex(key); var bucket = buckets[index]; KeyValuePair<string, int>? toRemove = null; foreach (var pair in bucket) { if (pair.Key == key) { toRemove = pair; break; } } if (toRemove != null) bucket.Remove(toRemove.Value); } public int Size() { int count = 0; foreach (var bucket in buckets) count += bucket.Count; return count; } }
Remember that updating a key does not increase size, and removing a key decreases size.
Keys after operations: "cat" (updated), "bird", "fish". "dog" was removed. So total 3 keys.
Examine the code below. When calling Get for a key not present, it throws an exception. What is the cause?
public int Get(string key) { int index = GetBucketIndex(key); var bucket = buckets[index]; foreach (var pair in bucket) { if (pair.Key == key) return pair.Value; } return bucket.First.Value; // Problematic line }
What happens if the bucket has no elements?
If the bucket is empty, bucket.First is null and accessing .Value throws InvalidOperationException.
Separate chaining is a collision resolution technique in HashMaps. What is its main advantage compared to open addressing?
Think about how collisions are stored in separate chaining.
Separate chaining stores collided elements in linked lists, so buckets can hold multiple items, avoiding immediate rehashing.
Given the following sequence of operations on a HashMap implemented with separate chaining, what will be printed?
var map = new SimpleHashMap(); map.Put("a", 1); map.Put("b", 2); map.Put("c", 3); map.Put("d", 4); map.Remove("b"); map.Put("e", 5); map.Put("a", 10); map.Remove("f"); var keys = map.GetAllKeys(); Console.WriteLine(string.Join(",", keys)); class SimpleHashMap { private readonly int size = 3; private LinkedList<KeyValuePair<string, int>>[] buckets; public SimpleHashMap() { buckets = new LinkedList<KeyValuePair<string, int>>[size]; for (int i = 0; i < size; i++) buckets[i] = new LinkedList<KeyValuePair<string, int>>(); } private int GetBucketIndex(string key) { return Math.Abs(key.GetHashCode()) % size; } public void Put(string key, int value) { int index = GetBucketIndex(key); var bucket = buckets[index]; foreach (var pair in bucket) { if (pair.Key == key) { bucket.Remove(pair); break; } } bucket.AddLast(new KeyValuePair<string, int>(key, value)); } public void Remove(string key) { int index = GetBucketIndex(key); var bucket = buckets[index]; KeyValuePair<string, int>? toRemove = null; foreach (var pair in bucket) { if (pair.Key == key) { toRemove = pair; break; } } if (toRemove != null) bucket.Remove(toRemove.Value); } public List<string> GetAllKeys() { var keys = new List<string>(); foreach (var bucket in buckets) { foreach (var pair in bucket) keys.Add(pair.Key); } return keys; } }
Check bucket indices and insertion order carefully.
Keys stored after operations are "a", "c", "d", "e" in that order by bucket traversal.
