Load factor, resizing and performance
↑How it works and why
Section titled “How it works and why”Load factor is typically count / bucketCount for chaining, or occupied slots / capacity for open addressing. As load factor rises, collision handling requires more work. Resizing creates a new backing array and rehashes all stored entries because the modulus has changed. This costs O(n) at resize time, but with geometric growth insertions can have amortized O(1) cost across many operations.
Hash codes must obey: if Equals(a,b) is true, the chosen hash function must return identical hash codes. Distinct keys may still collide. For mutable keys, prefer identity-independent, stable equality fields. Avoid relying on hash codes being stable across different .NET processes or versions.
C# and C++ examples
Section titled “C# and C++ examples”using System;using System.Collections.Generic;
var names = new HashSet<string>(StringComparer.OrdinalIgnoreCase);names.Add("ALICE");Console.WriteLine(names.Contains("alice")); // True
// Choose the comparer at collection creation time, not per lookup.#include <unordered_set>#include <string>#include <iostream>
std::unordered_set<std::string> names;names.insert("ALICE");std::cout << names.contains("ALICE") << '\n'; // 1std::cout << names.contains("alice") << '\n'; // 0// Default C++ string equality is case-sensitive.// For case-insensitive keys, define matching hash and equality functors.When and why to use it
Section titled “When and why to use it”Performance: State whether you mean average, expected, amortized or worst case. In adversarial collisions worst-case lookup can be linear in the number of keys. Try: In the interactive simulator change bucket count from 5 to 7 and watch every ID move to its new bucket.
Interactive hash table · HashSet and Dictionary
Language difference: StringComparer.OrdinalIgnoreCase makes the C# lookup case-insensitive, but std::unordered_set<std::string> is case-sensitive by default. A C++ alternative needs compatible custom hashing and equality rules.
