Sobes.tech
Middle

Wat moet je doen om je structuur op te slaan in een unordered_map?

sobes.tech AI

Antwoord van AI

Om een structuur als sleutel op te slaan in std::unordered_map, moet je het volgende voorzien:

  1. Hashfunctie: Bepaalt de hash-waarde voor een instantie van de structuur.
  2. Gelijkheidsoperator (operator==): Vergelijkt twee instanties van de structuur op gelijkheid.

Er zijn verschillende manieren om deze elementen te voorzien:

  • Overschrijf operator== binnen de structuur en specialiseert std::hash voor jouw structuur. Dit is de meest gebruikelijke en aanbevolen aanpak.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    
        bool operator==(const MyStruct& other) const {
            return id == other.id && name == other.name;
        }
    };
    
    // Specialisatie van std::hash voor MyStruct
    namespace std {
        template <>
        struct hash<MyStruct> {
            size_t operator()(const MyStruct& obj) const {
                size_t h1 = hash<int>()(obj.id);
                size_t h2 = hash<std::string>()(obj.name);
                return h1 ^ (h2 << 1);
            }
        };
    }
    
    // Voorbeeld gebruik in main
    int main() {
        std::unordered_map<MyStruct, int> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
        MyStruct key3 = {1, "Alice"}; // gelijkwaardig aan key1
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        if (my_map.count(key3)) {
            // my_map[key3] geeft 10
        }
    
        return 0;
    }
    
  • Voorzie hash- en vergelijkingsfuncties als aparte parameters in de template bij het declareren van unordered_map. Minder handig als je de structuur vaak als sleutel gebruikt, omdat je de types van comparator en hasher bij elke declaratie moet specificeren.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    };
    
    // Aparte hashfunctie
    struct MyStructHash {
        size_t operator()(const MyStruct& obj) const {
            size_t h1 = std::hash<int>()(obj.id);
            size_t h2 = std::hash<std::string>()(obj.name);
            return h1 ^ (h2 << 1);
        }
    };
    
    // Aparte vergelijkingsfunctie
    struct MyStructEqual {
        bool operator()(const MyStruct& lhs, const MyStruct& rhs) const {
            return lhs.id == rhs.id && lhs.name == rhs.name;
        }
    };
    
    // Voorbeeld gebruik in main
    int main() {
        std::unordered_map<MyStruct, int, MyStructHash, MyStructEqual> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        return 0;
    }
    

Belangrijke punten:

  • Correctheid van de hashfunctie: Voor elke twee sleutels a en b, als a == b, dan moet hash(a) gelijk zijn aan hash(b). Het omgekeerde is niet vereist (collisionen kunnen voorkomen).
  • Kwaliteit van de hashfunctie: Een goede hashfunctie verdeelt de hash-waarden gelijkmatig over verschillende sleutels, minimaliseert collisionen en verbetert de prestaties (O(1) gemiddeld).
  • Constantie: De operators voor vergelijking en hashfunctie moeten const zijn, omdat ze het sleutelobject niet mogen wijzigen.