Hash Map | GetHashCode(), Equals() | Algoritmo e Estrutura de dados
- Hash Map |
GetHashCode(),Equals()| Algoritmo e Estrutura de dados
Definição
- É um dicitionary.
[("augusto", "azul"), ("bernardo", "vermelho")] - Na maioria das vezes a complexidade temporal é O(n)
Hash Function-> pega a chave e faz alguma operação com ela para transformar em um número. Quando você solicita pela chave ela pega e converte para saber onde está
No C#, o dictionary é o equivalente ao hash map.
Explicação no C#
Quando você usa tipos personalizados como chave em um Dictionary<TKey, TValue> (ou qualquer estrutura baseada em hash), o .NET precisa de duas coisas para saber onde guardar os valores e como comparar chaves:
GetHashCode()— para calcular em qual “balde” do dicionário o item será colocado.Equals()— para verificar se duas chaves são “iguais” quando estão no mesmo balde.
Se essas duas operações não forem corretamente implementadas, o dicionário pode não encontrar um item mesmo que ele esteja lá — o que é um problema grave.
📌 Exemplo: usando um tipo personalizado como chave
class Pessoa
{
public string Nome { get; set; }
// Errado: Não sobrescrevemos GetHashCode e Equals
}
var dicionario = new Dictionary<Pessoa, string>();
dicionario[new Pessoa { Nome = "Maria" }] = "Desenvolvedora";
// Tenta acessar com outra instância com mesmo nome
var chave = new Pessoa { Nome = "Maria" };
bool existe = dicionario.ContainsKey(chave); // ❌ Retorna falso!
Mesmo que o Nome seja o mesmo, o dicionário trata os dois objetos como diferentes, porque ele usa a implementação padrão de GetHashCode() e Equals() — que compara por referência, não por valor.
✅ Solução: sobrescrever Equals e GetHashCode
class Pessoa
{
public string Nome { get; set; }
public override bool Equals(object obj)
{
if (obj is Pessoa outra)
return this.Nome == outra.Nome;
return false;
}
public override int GetHashCode()
{
return Nome?.GetHashCode() ?? 0;
}
}
Agora sim:
var dicionario = new Dictionary<Pessoa, string>();
dicionario[new Pessoa { Nome = "Maria" }] = "Desenvolvedora";
var chave = new Pessoa { Nome = "Maria" };
bool existe = dicionario.ContainsKey(chave); // ✅ Agora funciona!
🧠 Dica arquitetural:
Se for usar um tipo como chave sem controlar sua lógica de igualdade e hash, pode ser melhor:
- Torná-lo
record(C# 9+), que já implementaEqualseGetHashCodebaseado no conteúdo.
public record Pessoa(string Nome);
Esse record já funciona perfeitamente como chave em Dictionary.
Load Factor (Fator de Carga)
O load factor mede o nível de ocupação da tabela hash.
📌 Definição formal:
Load Factor = (número de elementos) ÷ (número de baldes disponíveis)
Exemplo simples:
- Suponha que a tabela hash tenha 100 posições (baldes).
- E você inseriu 60 elementos.
- Load Factor = 60 / 100 = 0.6 (ou 60%)
🧠 Por que importa?
Um load factor baixo:
- Menos colisões.
- Mais memória usada.
- Acesso mais rápido.
Um load factor alto:
- Mais colisões.
- Mais tempo de acesso (porque mais comparações são feitas por balde).
- Melhor uso da memória, mas com perda de performance.
✅ No Dictionary<TKey, TValue> do .NET:
- O
Dictionarytem um tamanho interno (capacidade) que aumenta automaticamente quando o load factor passa de um certo limite (geralmente próximo de0.75). - Quando isso acontece, ele rehash — ou seja, recalcula o hash de todas as chaves e redistribui nos novos baldes.
Hash Collisions (Colisões de Hash)
Uma colisão ocorre quando duas chaves diferentes geram o mesmo hash code e são colocadas no mesmo balde.
Exemplo:
var dicionario = new Dictionary<int, string>();
dicionario[1] = "um";
dicionario[101] = "cento e um"; // Suponha que 1 e 101 caiam no mesmo balde
🧠 O que o .NET faz?
- Usa encadeamento aberto (em versões antigas) ou endereçamento aberto com sondagem (versões mais recentes do .NET).
- Ou seja, dentro de cada balde, ele mantém uma estrutura para comparar as chaves, usando
Equals.
🚨 Impacto das colisões:
- Se houver muitas colisões, o dicionário se comporta mais como uma lista encadeada — perde o tempo constante
O(1)e pode ir paraO(n)no pior caso. - É por isso que é essencial ter uma boa função de hash e manter o load factor em um nível saudável.