Sobes.tech
Middle

O que é necessário fazer para armazenar sua estrutura em unordered_map?

sobes.tech IA

Resposta da IA

Para armazenar uma estrutura como chave em std::unordered_map, é necessário fornecer:

  1. Função de hashing (hash function): Encontra o valor de hash para uma instância da estrutura.
  2. Operador de comparação de igualdade (operator==): Compara duas instâncias da estrutura para verificar se são iguais.

Existem várias formas de fornecer esses elementos:

  • Sobrecarga de operator== dentro da estrutura e especialização de std::hash para a sua estrutura. Esta é a abordagem mais comum e recomendada.

    #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;
        }
    };
    
    // Especialização de std::hash para 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);
            }
        };
    }
    
    // Exemplo de uso em main
    int main() {
        std::unordered_map<MyStruct, int> my_map;
        MyStruct key1 = {1, "Alice"};
        MyStruct key2 = {2, "Bob"};
        MyStruct key3 = {1, "Alice"}; // equivalente a key1
    
        my_map[key1] = 10;
        my_map[key2] = 20;
    
        if (my_map.count(key3)) {
            // my_map[key3] devolverá 10
        }
    
        return 0;
    }
    
  • Proporcionar funções de hashing e comparação como parâmetros separados na declaração de unordered_map. Menos conveniente se usar frequentemente a estrutura como chave, pois precisa especificar os tipos de comparador e hash em cada declaração do contêiner.

    #include <unordered_map>
    #include <string>
    #include <functional>
    
    struct MyStruct {
        int id;
        std::string name;
    };
    
    // Função de hashing separada
    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);
        }
    };
    
    // Função de comparação separada
    struct MyStructEqual {
        bool operator()(const MyStruct& lhs, const MyStruct& rhs) const {
            return lhs.id == rhs.id && lhs.name == rhs.name;
        }
    };
    
    // Exemplo de uso em 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;
    }
    

Pontos importantes:

  • Correção da função de hash: Para quaisquer dois chaves a e b, se a == b, então hash(a) deve ser igual a hash(b). O inverso não é necessário (colisões podem ocorrer).
  • Qualidade da função de hash: Uma boa função de hash distribui uniformemente os valores de hash para diferentes chaves, minimizando colisões e melhorando o desempenho (O(1) em média).
  • Constância: Os operadores de comparação e a função de hash devem ser const, pois não devem modificar o objeto chave.