{
    "api": "YAML JSON TOON Database",
    "version": "1.0.0",
    "format": "json",
    "dataset": {
        "id": 27,
        "slug": "hash-tables",
        "title": "Hash Tables & Hash Functions",
        "description": "Hash table implementations, collision resolution strategies, hash functions, load factor, and performance characteristics.",
        "category": "Data Structures",
        "category_slug": "data-structures",
        "tags": "hash-tables,dictionaries,associative-arrays,collision-resolution,hashing",
        "view_count": 0,
        "created_at": 1777673262,
        "updated_at": 1777673262
    },
    "data": {
        "core_concepts": [
            {
                "component": "Hash Function",
                "purpose": "Maps arbitrary key to integer index in hash table array",
                "properties": ["Deterministic (same key → same hash)", "Fast to compute", "Uniform distribution", "Minimizes collisions"],
                "common_functions": ["MurmurHash3", "CityHash", "FNV-1a", "SHA-256 (cryptographic, slow)", "MD5 (cryptographic, deprecated)"],
                "example": "h(k) = (a × k + b) mod m (affine hash for integers)",
                "notes": "Cryptographic hashes (SHA, MD5) are slow; non-cryptographic preferred for hash tables"
            },
            {
                "component": "Load Factor (α)",
                "definition": "Ratio of number of entries to number of buckets (n / m)",
                "threshold": "Typically 0.75 for separate chaining, 0.5-0.7 for open addressing",
                "rehashing": "When α exceeds threshold, resize table (usually double) and rehash all entries",
                "time_impact": "Amortized O(1) if resizing infrequent; worst-case O(n) during resize",
                "notes": "Higher α → more collisions, slower lookups; lower α → wasted memory"
            },
            {
                "component": "Collision Resolution",
                "strategies": ["Separate Chaining", "Open Addressing (Linear/Quadratic/Double Hashing)"],
                "description": "Method to handle multiple keys mapping to same bucket index"
            }
        ],
        "collision_strategies": {
            "separate_chaining": {
                "structure": "Each bucket is linked list (or tree) of entries; hash(key) → bucket index → traverse list",
                "complexity": {
                    "avg_search": "O(1 + α) = O(1) if α constant",
                    "worst_search": "O(n) if all keys collide",
                    "insert": "O(1) (prepend to list)",
                    "delete": "O(1) if have pointer, else O(length of chain)"
                },
                "pros": ["Simple", "Handles any load factor", "Deletion easy", "Never full (can always insert)"],
                "cons": ["Memory overhead (pointers per node)", "Cache unfriendly (linked list scattered)"],
                "optimization": "Convert linked list to balanced BST (e.g., Java 8+) when chain length exceeds threshold (e.g., 8) → O(log n) worst case"
            },
            "open_addressing": {
                "structure": "All entries stored directly in array; collision → probe sequence to find next available slot",
                "probing_methods": {
                    "linear": "h(k, i) = (h'(k) + i) mod m — simple but primary clustering",
                    "quadratic": "h(k, i) = (h'(k) + c₁i + c₂i²) mod m — reduces clustering but secondary clustering remains",
                    "double_hashing": "h(k, i) = (h₁(k) + i × h₂(k)) mod m — minimal clustering, best performance; h₂(k) must be relatively prime to m"
                },
                "complexity": {
                    "avg_search": "O(1 / (1 - α)) for successful, O(1 / (1 - α)²) for unsuccessful",
                    "worst_search": "O(n) if table nearly full",
                    "insert": "Same as search (find empty slot)",
                    "delete": "Complex — cannot simply remove (breaks probe chain); use tombstone marker"
                },
                "pros": ["No pointer overhead (cache friendly)", "Lower memory use"],
                "cons": ["More sensitive to load factor", "Deletion tricky (tombstones accumulate)", "Clustering issues (linear/quadratic)"],
                "notes": "Table load should stay ≤ 0.5-0.7 for good performance; tombstone cleanup periodic rehash"
            }
        },
        "hash_table_types": [
            {
                "name": "HashMap / Dictionary",
                "implementation": "Array of buckets + hash function + collision resolution",
                "languages": ["Python: dict", "Java: HashMap", "JavaScript: Object/Map", "C++: std::unordered_map", "Go: map"],
                "avg_operations": "O(1)",
                "notes": "Most common associative array; maintains insertion order in some implementations (Python 3.7+)"
            },
            {
                "name": "HashSet",
                "implementation": "Hash table storing only keys (no values)",
                "languages": ["Python: set", "Java: HashSet", "C++: std::unordered_set"],
                "use_cases": ["Duplicate elimination", "Membership testing", "Set operations (union, intersection)"],
                "notes": "Backed by hash table; hash of key determines bucket"
            },
            {
                "name": "Concurrent Hash Map",
                "implementation": "Lock striping or lock-free segments for thread-safe access",
                "languages": ["Java: ConcurrentHashMap", "C++: tbb::concurrent_hash_map", "Rust: dashmap"],
                "features": ["Fine-grained locking (segment/ stripe)", "Lock-free reads", "High concurrency"],
                "notes": "Traditional HashMap requires external synchronization (synchronized/mutex); concurrent maps scale to many threads"
            }
        ],
        "design_considerations": {
            "choose_hash_function": {
                "integers": "Multiplicative: (a × k) >> shift or modulo prime",
                "strings": "Polynomial rolling hash (h = Σ char[i] × p^i mod m) or MurmurHash3",
                "objects": "Combine field hashes: hash = 31 × (31 × seed + field1.hash) + field2.hash (Java style)"
            },
            "avoid_collisions": {
                "prime_bucket_count": "Use prime number of buckets (reduces clustering with mod)",
                "good_hash": "Uniform distribution; test with real key distribution",
                "dynamic_resize": "Resize when α exceeds threshold (typically 0.75)"
            },
            "when_not_to_use": {
                "ordered_operations": "Need sorted keys → use BST (TreeMap)",
                "range_queries": "Need keys in range → BST or B-tree",
                "memory_constrained": "Hash tables have overhead (pointers/buckets)",
                "extremely_large_keys": "Consider key interning or perfect hash"
            }
        }
    }
}
