Sobes.tech
Middle

Какво трябва да направите, за да съхраните структурата си в unordered_map?

sobes.tech AI

Отговор от AI

За да съхранявате структура като ключ в std::unordered_map, трябва да предоставите:

  1. Функция за хеширане (hash function): Намерете хеш стойността за инстанция на структурата.
  2. Оператор за сравнение за равенство (operator==): Сравнява две инстанции на структурата за равенство.

Има няколко начина да предоставите тези елементи:

  • Пренапишете operator== вътре в структурата и специализирайте std::hash за вашата структура. Това е най-често срещаният и препоръчителен подход.

    #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;
        }
    };
    
    // Специализация на std::hash за 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);
            }
        };
    }
    
    // Пример за използване в main
    int main() {
        std::unordered_map<MyStruct, int> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
        MyStruct key3 = {1, "Alice"}; // еквивалентен на key1
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        if (my_map.count(key3)) {
            // my_map[key3] ще даде 10
        }
    
        return 0;
    }
    
  • Да предоставите функциите за хеширане и сравнение като отделни параметри на шаблона при обявяване на unordered_map. По-малко удобно, ако често използвате структурата като ключ, тъй като трябва да посочвате типовете на компаратора и хешера при всяко обявяване на контейнера.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    };
    
    // Отделна функция за хеширане
    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);
        }
    };
    
    // Отделна функция за сравнение (или функтор)
    struct MyStructEqual {
        bool operator()(const MyStruct& lhs, const MyStruct& rhs) const {
            return lhs.id == rhs.id && lhs.name == rhs.name;
        }
    };
    
    // Пример за използване в 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;
    }
    

Важни моменти:

  • Коректност на hash функцията: За всеки два ключа a и b, ако a == b, тогава hash(a) трябва да е равно на hash(b). Обратното не е задължително (колизии могат да се случат).
  • Качество на hash функцията: Добра hash функция равномерно разпределя стойностите за различни ключове, минимизирайки колизиите и подобрявайки производителността (O(1) средно).
  • Константност: Операторите за сравнение и hash функцията трябва да бъдат const, тъй като не трябва да променят обекта на ключа.