O conto que tabelas de dispersão são amortizados é uma mentira uma simplificação. Θ(1)
Isso só é verdade se:
- A quantidade de dados em hash por item é trivial em comparação com o número de K eys e a velocidade do hash de um K ey é rápida - .
- O número de C ollisions é pequena - .
- Nós não ter em conta o tempo necessário para R esize tabela hash - .k
c
r
Seqüências grandes de hash
Se a primeira suposição for falsa, o tempo de execução aumentará para .
Definitivamente, isso é verdade para cadeias grandes, mas para cadeias grandes uma comparação simples também teria um tempo de execução de . Portanto, um hash não é assintoticamente mais lento, embora o hash sempre seja mais lento do que uma comparação simples, porque a comparação tem uma opção de exclusão inicial logo , e hash sempre tem que hash a cadeia completa , . Θ(k)
Θ(k)O(1)Ω(k)O(k)Ω(k)
Observe que números inteiros crescem muito lentamente. 8 bytes podem armazenar valores de até ; 8 bytes é uma quantidade trivial de hash.
Se você deseja armazenar bigints, pense nelas como strings. 1018
Algoritmo de hash lento
Se o valor gasto em hash não é trivial em comparação com o armazenamento dos dados, obviamente a suposição se torna insustentável.
A menos que um hash criptográfico seja usado, isso não deve ser um problema.Θ(1)
O que importa é que . Enquanto isso acontecer, é uma afirmação justa.n >> kΘ(1)
Muitas colisões
Se a função de hash for ruim, ou a tabela de hash for pequena, ou se o tamanho da tabela de hash for desagradável, as colisões serão frequentes e o tempo de execução passará para .
A função de hash deve ser escolhida de modo que as colisões sejam raras e, ao mesmo tempo, sejam o mais rápido possível, quando houver dúvida, opte por menos colisões às custas de hash mais lento.
Uma regra prática é que a tabela de hash deve sempre ter menos de 75% de sua capacidade.
E o tamanho da tabela de hash não deve ter nenhuma correlação com a função de hash.
Frequentemente, o tamanho da tabela de hash é (relativamente) primo. O(log(n))
Redimensionando a tabela de hash
Como uma tabela de hash quase cheia causará muitas colisões e uma tabela de hash grande (vazia) é um desperdício de espaço, muitas implementações permitem que a tabela de hash cresça (e encolha!) Conforme necessário.
O crescimento de uma tabela pode envolver uma cópia completa de todos os itens (e possivelmente uma reorganização), porque o armazenamento precisa ser contínuo por razões de desempenho.
Somente em casos patológicos o redimensionamento da tabela de hash será um problema, para que os redimensionamentos (caros, mas raros) sejam amortizados em muitas chamadas.
Tempo de execução
Portanto, o tempo de execução real de uma tabela de hash é .
Cada , , em média é assumido como uma (pequena) constante no tempo de execução amortizado e, portanto, dizemos que é uma demonstração justa. Θ(kcr)
kcrΘ(1)
Para voltar às suas perguntas Por favor, desculpe-me por parafrasear, tentei extrair diferentes conjuntos de significados, fique à
vontade para comentar se perdi alguns
Você parece estar preocupado com o comprimento da saída da função hash. Vamos chamar isso de ( geralmente é considerado o número de itens a serem hash). será porque m precisa identificar exclusivamente uma entrada na tabela de hash.
Isso significa que m cresce muito lentamente. Com 64 bits, o número de entradas da tabela de hash ocupará uma porção considerável da RAM disponível mundialmente. Com 128 bits, excederá em muito o armazenamento em disco disponível no planeta Terra.
Produzindo um hash de 128 bits não é muito mais difícil do que um bit 32 de hash, de modo nenhum , o tempo para criar um hash não é (ou se preferir). mnmlog(n)
O(m)O(log(n))
A função hash passando por bits do elemento vai levar de tempo. log(n)Θ(log(n))
Mas a função hash não passa por bits de elementos.
Por um item (!!), ele passa apenas pelos dados .
Além disso, o comprimento da entrada (k) não tem relação com o número de elementos. Isso é importante, porque alguns algoritmos sem hash precisam examinar muitos elementos na coleção para encontrar um elemento (não) correspondente.
A tabela de hash faz apenas 1 ou 2 comparações por item em consideração, em média, antes de chegar a uma conclusão. log(n)
O(k)
Por que as tabelas de hash são eficientes para armazenar elementos de comprimento variável?
Como, independentemente do comprimento da entrada ( ), o comprimento da saída ( ) é sempre o mesmo, as colisões são raras e o tempo de pesquisa é constante.
No entanto, quando o comprimento da chave cresce em comparação com o número de itens na tabela de hash ( ), a história muda ...km
kn
Por que as tabelas de hash são eficientes para armazenar grandes seqüências de caracteres?
As tabelas de hash não são muito eficientes para cadeias muito grandes.
Se for (ou seja, o tamanho da entrada é bastante grande comparado ao número de itens na tabela de hash), não podemos mais dizer que o hash tem um tempo de execução constante, mas devemos mudar para um tempo de execução de especialmente porque não há saída precoce. Você precisa fazer o hash da chave completa. Se você estiver armazenando apenas um número limitado de itens, pode ser muito melhor usar um armazenamento classificado, porque, ao comparar você pode optar por sair assim que houver uma diferença. not n>>kΘ(k)k1 ≠ k2
No entanto, se você conhece seus dados, pode optar por não hash da chave completa, mas apenas a parte volátil (conhecida ou assumida) dela, restaurando a propriedade enquanto mantém as colisões sob controle. Θ(1)
Constantes ocultas
Como todos deveriam saber significa simplesmente que o tempo por elemento processado é uma constante. Essa constante é um pouco maior para hash do que para comparação simples.
Para tabelas pequenas, uma pesquisa binária será mais rápida que uma pesquisa de hash, porque, por exemplo, 10 comparações binárias podem muito bem ser mais rápidas que um único hash.
Para conjuntos de dados pequenos, alternativas para tabelas de hash devem ser consideradas.
É em grandes conjuntos de dados que as tabelas de hash realmente brilham.Θ(1)