Sobes.tech
Middle

Mit kell tenni ahhoz, hogy a szerkezetedet unordered_map-ben tárold?

sobes.tech MI

Válasz az MI-től

Ahhoz, hogy egy struktúrát kulcsként tároljunk az std::unordered_map-ban, meg kell adni:

  1. Hash függvény: Megkeresi a hash értéket a struktúra példányára.
  2. Egyenlőség operátor (operator==): Összehasonlít két struktúra példányt egyenlőség szempontjából.

Ezeket az elemeket többféleképpen lehet biztosítani:

  • Felülírni az operator==-t a struktúrában és specializálni az std::hash-t a struktúrádhoz. Ez a leggyakoribb és ajánlott megközelítés.

    #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;
        }
    };
    
    // Az `std::hash` specializálása a MyStruct-hez
    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);
            }
        };
    }
    
    // Használati példa a main-ben
    int main() {
        std::unordered_map<MyStruct, int> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
        MyStruct key3 = {1, "Alice"}; // ekvivalens a key1-gyel
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        if (my_map.count(key3)) {
            // my_map[key3] 10 lesz
        }
    
        return 0;
    }
    
  • Biztosítani a hash és összehasonlító függvényeket külön paraméterként az unordered_map deklarációjánál. Ez kevésbé kényelmes, ha gyakran használod a struktúrát kulcsként, mert minden alkalommal meg kell adni a típusokat.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    };
    
    // Külön hash függvény
    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);
        }
    };
    
    // Külön összehasonlító függvény (vagy funktor)
    struct MyStructEqual {
        bool operator()(const MyStruct& lhs, const MyStruct& rhs) const {
            return lhs.id == rhs.id && lhs.name == rhs.name;
        }
    };
    
    // Használati példa a main-ben
    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;
    }
    

Fontos megjegyzések:

  • A hash függvény helyessége: Bármely két kulcs a és b esetén, ha a == b, akkor hash(a) és hash(b) ugyanaz legyen. A fordítva nem kötelező (kollíziók lehetségesek).
  • A hash függvény minősége: Egy jó hash függvény egyenletesen osztja el a hash értékeket különböző kulcsok között, minimalizálva a kollíziókat és javítva a teljesítményt (O(1) átlagosan).
  • Állandóság: A összehasonlító operátorok és a hash függvény const típusúak kell legyenek, mivel nem szabad módosítaniuk a kulcs objektumát.