Sobes.tech
Middle

Ce trebuie să faci pentru a-ți stoca structura în unordered_map?

sobes.tech AI

Răspuns de la AI

Pentru a stoca o structură ca și cheie în std::unordered_map, trebuie să furnizați:

  1. Funcția de hash (hash function): Găsește valoarea hash pentru o instanță a structurii.
  2. Operatorul de comparare pentru egalitate (operator==): Compară două instanțe ale structurii pentru egalitate.

Există mai multe moduri de a furniza aceste elemente:

  • Supraincarcă operator== în interiorul structurii și specializează std::hash pentru structura ta. Aceasta este abordarea cea mai comună și recomandată.

    #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;
        }
    };
    
    // Specializare a std::hash pentru 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);
            }
        };
    }
    
    // Exemplu de utilizare în main
    int main() {
        std::unordered_map<MyStruct, int> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
        MyStruct key3 = {1, "Alice"}; // echivalent cu key1
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        if (my_map.count(key3)) {
            // my_map[key3] va returna 10
        }
    
        return 0;
    }
    
  • Furnizați funcții de hash și comparare ca parametri separați în șablonul de declarație al unordered_map. Mai puțin convenabil dacă folosiți frecvent structura ca și cheie, deoarece trebuie să specificați tipurile comparatorului și hash-ului la fiecare declarație a containerului.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    };
    
    // Funcție de hash separată
    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);
        }
    };
    
    // Funcție de comparare separată
    struct MyStructEqual {
        bool operator()(const MyStruct& lhs, const MyStruct& rhs) const {
            return lhs.id == rhs.id && lhs.name == rhs.name;
        }
    };
    
    // Exemplu de utilizare în 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;
    }
    

Puncte importante:

  • Corectitudinea funcției de hash: Pentru orice două chei a și b, dacă a == b, atunci hash(a) trebuie să fie egal cu hash(b). Inversul nu este necesar (coliziile pot apărea).
  • Calitatea funcției de hash: O funcție de hash bună distribuie uniform valorile hash pentru diferite chei, minimizând coliziunile și îmbunătățind performanța (O(1) în medie).
  • Constanța: Operatorii de comparare și funcția de hash trebuie să fie const, deoarece nu trebuie să modifice obiectul cheie.