Menu
Coddy logo textTech

Tabela Hash

Última atualização

Uma tabela hash armazena itens em um arranjo de baldes. Para inserir ou encontrar uma chave, ela passa a chave por uma função hash e toma o resultado módulo o número de baldes - isso fornece o índice do balde em O(1). Pressione reproduzir acima para ver cada chave ser convertida em hash para um balde e armazenada, e depois uma busca saltar direto para o balde correto.

Quando duas chaves caem no mesmo balde - uma colisão - esta visualização usa encadeamento separado: cada balde contém uma pequena lista, e as chaves que colidem são anexadas a ela. Enquanto a tabela não estiver cheia demais (um fator de carga baixo) e o hash distribuir bem as chaves, as cadeias permanecem curtas e inserção, busca e remoção são O(1) em média.

Complexidade de tempo

OperaçãoMédiaPior caso
InserirO(1)O(n) (todas as chaves colidem)
BuscaO(1)O(n)
RemoverO(1)O(n)
EspaçoO(n)O(n)

Conceitos-chave

TermoSignificado
Função hashMapeia uma chave para um índice de balde
ColisãoDuas chaves caem no mesmo balde
Encadeamento separadoCada balde contém uma lista de entradas que colidem
Endereçamento abertoAlternativa: sondar o próximo slot livre
Fator de cargaentradas / baldes - determina o redimensionamento

Exemplo resolvido

Inserindo as chaves 20, 34, 9, 13 em uma tabela com 7 baldes, usando hash(k) = k % 7:

PassoEstruturaAção
Inserir 20balde 6: [20]20 % 7 = 6, balde 6 vazio, armazenar 20
Inserir 34balde 6: [20, 34]34 % 7 = 6, colisão com 20, anexar 34 à cadeia
Inserir 9balde 2: [9]9 % 7 = 2, balde 2 vazio, armazenar 9
Inserir 13balde 6: [20, 34, 13]13 % 7 = 6, colisão, anexar 13 à cadeia do balde 6
Buscar 34balde 6: [20, 34, 13]34 % 7 = 6, percorrer cadeia: 20 não, 34 corresponde - encontrado

Quando usar uma tabela hash

Use quandoEvite quando
Você precisa de inserção, busca e remoção por chave em O(1) médioVocê precisa manter as chaves ordenadas - use uma BST balanceada
As chaves não têm ordem útil e você só testa pertencimento por correspondência exataVocê precisa de consultas por intervalo ou buscas da chave mais próxima
Você pode arcar com memória extra para baldes e um fator de carga baixoA memória é extremamente limitada e cada byte conta
Existe uma boa função hash para o seu tipo de chaveA latência do pior caso deve ser limitada - as colisões a tornam O(n)

Código de Hash Table

Uma implementação limpa e executável de Hash Table em Python, JavaScript, Java, C++, C. Escolha uma linguagem, copie o código ou abra-o já carregado no Playground da Coddy.

Código de Hash Table em Python

Python
1class HashTable:2    def __init__(self, size=8):3        self.size = size4        self.buckets = [[] for _ in range(size)]5
6    def _index(self, key):7        # Hash the key to a bucket; different keys can collide8        return sum(ord(ch) for ch in key) % self.size9
10    def set(self, key, value):11        bucket = self.buckets[self._index(key)]12        for i, (k, _) in enumerate(bucket):13            if k == key:14                bucket[i] = (key, value)  # update existing key15                return16        bucket.append((key, value))  # chain on collision17
18    def get(self, key):19        for k, v in self.buckets[self._index(key)]:20            if k == key:21                return v22        raise KeyError(key)23
24    def delete(self, key):25        bucket = self.buckets[self._index(key)]26        for i, (k, _) in enumerate(bucket):27            if k == key:28                del bucket[i]29                return30        raise KeyError(key)31
32
33table = HashTable()34table.set("apple", 3)35table.set("banana", 7)36table.set("cherry", 5)37
38print("apple  ->", table.get("apple"))39print("banana ->", table.get("banana"))40table.set("apple", 10)41print("apple  ->", table.get("apple"))42table.delete("banana")43print("bucket sizes:", [len(b) for b in table.buckets])
Execute este código no Playground de Python

Perguntas frequentes sobre a tabela hash

O que é uma colisão de hash e como ela é resolvida?
Uma colisão ocorre quando duas chaves diferentes caem no mesmo balde. As duas soluções comuns são o encadeamento separado (cada balde contém uma lista e as chaves que colidem são anexadas - mostrado aqui) e o endereçamento aberto (sondar o próximo slot vazio do arranjo). Ambos mantêm as buscas corretas; diferem no layout de memória e no desempenho sob carga alta.
Qual é a complexidade de tempo de uma tabela hash?
Inserção, busca e remoção são O(1) em média quando a função hash distribui as chaves uniformemente e o fator de carga é mantido baixo. No pior caso - todas as chaves colidindo em um único balde - elas se degradam para O(n), por isso uma boa função hash e o redimensionamento importam.
O que é um fator de carga?
O fator de carga é o número de entradas armazenadas dividido pelo número de baldes. À medida que cresce, as cadeias ficam mais longas e as operações mais lentas, por isso a maioria das tabelas hash redimensiona (refaz o hash para um arranjo maior) quando ele ultrapassa um limite como 0.75.
Quando devo usar uma tabela hash em vez de uma árvore binária de busca?
Use uma tabela hash quando você só precisa de buscas por correspondência exata e quer velocidade O(1) média sem requisito de ordem. Use uma árvore binária de busca balanceada quando você precisa de chaves ordenadas, consultas por intervalo ou buscas de predecessor/sucessor, algo que uma tabela hash não faz de forma eficiente. Uma BST oferece operações O(log n) garantidas, enquanto uma tabela hash troca essa garantia por um desempenho médio mais rápido.
Qual é a diferença entre encadeamento separado e endereçamento aberto?
O encadeamento separado armazena as chaves que colidem em uma lista por balde, de modo que um balde pode conter muitas entradas e a tabela nunca fica realmente cheia. O endereçamento aberto mantém tudo no próprio arranjo e sonda o próximo slot livre em uma colisão, o que é amigável ao cache mas se degrada bruscamente quando o fator de carga se aproxima de 1 e requer tratamento cuidadoso de remoção. O encadeamento tolera fatores de carga mais altos; o endereçamento aberto usa a memória de forma mais compacta.
Por que não posso confiar que uma tabela hash mantenha minhas chaves na ordem de inserção ou de ordenação?
Uma função hash espalha deliberadamente as chaves entre os baldes para evitar aglomeração, então a ordem de iteração reflete o layout dos baldes, não a ordem de inserção ou de ordenação. Se você precisa de ordem, use um mapa/árvore ordenado ou uma estrutura como um mapa com ordem de inserção (por exemplo, o dict do Python preserva a ordem de inserção, mas isso é uma garantia da linguagem, não uma propriedade inerente da tabela hash). Nunca presuma que a ordem de iteração corresponde à forma como você inseriu as chaves, a menos que a linguagem prometa isso explicitamente.
Coddy programming languages illustration

Domine algoritmos com a Coddy

COMEÇAR