Sobes.tech
Middle

Was muss getan werden, um seine Struktur in einer unordered_map zu speichern?

sobes.tech KI

Antwort von AI

Um eine Struktur als Schlüssel in std::unordered_map zu speichern, ist es notwendig,:

  1. Hash-Funktion: Findet den Hash-Wert für eine Instanz der Struktur.
  2. Gleichheitsoperator (operator==): Vergleicht zwei Instanzen der Struktur auf Gleichheit.

Es gibt mehrere Möglichkeiten, diese Elemente bereitzustellen:

  • Überschreiben von operator== innerhalb der Struktur und Spezialisierung von std::hash für deine Struktur. Dies ist der gebräuchlichste und empfohlene Ansatz.

    #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;
        }
    };
    
    // Spezialisierung von std::hash für 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);
            }
        };
    }
    
    // Beispiel in main
    int main() {
        std::unordered_map<MyStruct, int> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
        MyStruct key3 = {1, "Alice"}; // äquivalent zu key1
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        if (my_map.count(key3)) {
            // my_map[key3] gibt 10 zurück
        }
    
        return 0;
    }
    
  • Bereitstellen von Hash- und Vergleichsfunktionen als separate Parameter in der Vorlage bei der Deklaration von unordered_map. Weniger bequem, wenn du die Struktur häufig als Schlüssel verwendest, da du die Typen des Vergleichers und des Hashers bei jeder Deklaration des Containers angeben musst.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    };
    
    // Separate Hash-Funktion
    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);
        }
    };
    
    // Separate Vergleichsfunktion
    struct MyStructEqual {
        bool operator()(const MyStruct& lhs, const MyStruct& rhs) const {
            return lhs.id == rhs.id && lhs.name == rhs.name;
        }
    };
    
    // Beispiel 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;
    }
    

Wichtige Punkte:

  • Korrektheit der Hash-Funktion: Für beliebige zwei Schlüssel a und b, wenn a == b, dann muss hash(a) gleich hash(b) sein. Das Gegenteil ist nicht erforderlich (Kollisionen sind möglich).
  • Qualität der Hash-Funktion: Eine gute Hash-Funktion verteilt die Hash-Werte gleichmäßig für verschiedene Schlüssel, minimiert Kollisionen und erhöht die Leistung (O(1) im Durchschnitt).
  • Konstanz: Die Operatoren für Vergleich und Hash-Funktion sollten const sein, da sie das Objekt des Schlüssels nicht verändern dürfen.