Conteúdos da cadeira

Tabelas de dispersão

Funções de dispersão, colisões por encadeamento e endereçamento aberto, e o fator de carga.

Markdown

Perguntar sobre esta página

ChatGPTClaudePerplexityGeminiCopiar e abrir

Envia o link e pede à IA para ler a página. No Gemini, cola a pergunta copiada.

Ver pergunta para copiar
Nesta página

A ABP pesquisa em O(logn)O(\log n) comparando chaves. Uma tabela de dispersão tenta O(1)O(1): em vez de procurar a chave, calcula onde ela está. O cálculo raramente é perfeito, e esta página é sobre gerir as imperfeições sem perder o tempo constante.

A ideia

Uma função de dispersão hh transforma cada chave num índice da tabela: para guardar o par (chave, valor), põe-no na posição h(chave)h(chave); para o ler, recalcula h(chave)h(chave) e vai lá. Uma boa função espalha as chaves uniformemente pelos índices, é rápida e determinista (a mesma chave dá sempre o mesmo índice). O exemplo canónico para chaves inteiras é h(k)=kmodmh(k) = k \bmod m, sendo mm o tamanho da tabela.

Duas chaves com o mesmo índice fazem uma colisão. Colisões são inevitáveis quando há mais chaves que posições, e prováveis muito antes disso: com 23 pessoas numa sala, a probabilidade de dois aniversários coincidirem já passa de metade. Por isso a tabela precisa de uma estratégia de colisões, não de esperança.

Encadeamento

No encadeamento (chaining), cada posição guarda uma lista ligada de pares. Inserir 5 chaves numa tabela de tamanho 7 com h(k)=kmod7h(k) = k \bmod 7, pela ordem 12, 25, 9, 30, 18:

  • 12mod7=512 \bmod 7 = 5: posição 5 fica [12][12].
  • 25mod7=425 \bmod 7 = 4: posição 4 fica [25][25].
  • 9mod7=29 \bmod 7 = 2: posição 2 fica [9][9].
  • 30mod7=230 \bmod 7 = 2: colisão com o 9; a posição 2 fica [9,30][9, 30].
  • 18mod7=418 \bmod 7 = 4: colisão com o 25; a posição 4 fica [25,18][25, 18].

Pesquisar o 30 recalcula o índice 2 e percorre a cadeia: compara com 9 (diferente), compara com 30 (igual). Duas comparações em vez de uma, o preço da colisão. Apagar remove o nó da cadeia, como numa lista ligada.

O fator de carga α=n/m\alpha = n/m (chaves por posição) prevê o custo: com boa dispersão, cada cadeia tem cerca de α\alpha elementos e a pesquisa custa O(1+α)O(1 + \alpha). Aqui α=5/70,71\alpha = 5/7 \approx 0{,}71. Quando α\alpha cresce, a tabela redimensiona: cria uma tabela maior e reinsere tudo (rehashing). Redimensionar custa O(n)O(n), mas acontece raramente, por isso o custo amortizado por inserção continua O(1)O(1), como na fila de duas pilhas.

Endereçamento aberto

No endereçamento aberto, os pares vivem todos dentro da tabela; em colisão, tenta-se a próxima posição livre segundo uma sondagem. Na sondagem linear tenta-se h(k),h(k)+1,h(k)+2,h(k), h(k)+1, h(k)+2, \dots (módulo mm). É simples e amiga da cache, mas forma aglomerados: posições ocupadas atraem mais tentativas, que ocupam mais posições. A sondagem quadrática e a dispersão dupla espalham melhor as tentativas.

O preço do endereçamento aberto aparece na remoção: apagar uma chave a meio de uma sequência de sondagem parte o caminho das chaves seguintes, por isso marca-se a posição como apagada (tombstone) em vez de livre. As remoções acumulam lixo e obrigam a redimensionar mais cedo. Escolhe encadeamento quando as remoções são frequentes e a memória não aperta; endereçamento aberto quando a tabela cabe na cache e as chaves são estáveis.

Ver o ficheiro no GitHub

À tua maneira

Escolhe como preferes ler.

Aparência
Ajustar cores e largura
Cor de destaque do tema FEUP
Tipo de letra

Álgebra, lógica e uma ideia de cada vez.

As tuas escolhas ficam guardadas neste navegador.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.