Existem várias técnicas que garantem que as pesquisas sempre exijam operações O (1), mesmo no pior caso.
Como posso determinar se uma tabela de hash tem chance de ter operações O (1) e possivelmente quais técnicas usar na minha função de hash?
O pior caso ocorre quando algum invasor mal-intencionado (Mallory) deliberadamente fornece dados que Mallory selecionou especificamente para tornar o sistema lento.
Depois de escolher uma função hash específica, é provavelmente otimista demais supor que Mallory nunca descobrirá qual função hash você escolheu. Depois que Mallory descobrir qual função de hash você escolheu, se você permitir que Mallory lhe forneça muitos dados a serem inseridos em sua tabela de hash usando essa função de hash, você estará condenado: Mallory pode gerar rapidamente internamente bilhões de itens de dados, hash-os com o seu A função hash para encontrar quais itens de dados provavelmente colidirão e, em seguida, fornecerá milhões de itens de dados que podem colidir, resultando em pesquisas que são muito mais lentas que O (1).
Todas as técnicas que garantem "pesquisas O (1) mesmo nos piores casos" evitam esse problema, fazendo um pouco de trabalho extra em cada inserção para garantir que, no futuro, todas as pesquisas possíveis tenham êxito no tempo O (1) . Em particular, assumimos (no pior caso) que Mallory descobrirá, mais cedo ou mais tarde, qual função de hash estamos usando; mas ele só tem a chance de inserir alguns itens de dados antes de escolher uma função de hash diferente - hash de tabulação ou algum outro hash universal - um que selecionamos especialmente para que todos os dados que temos até agora possam ser pesquisados em 2 ou 3 sondas - ou seja, O (1). Como selecionamos essa função aleatoriamente, podemos ter certeza de que Mallory não saberá qual função escolhemos por um tempo. Mesmo se Malloryimediatamente nos fornece dados que, mesmo com essa nova função de hash, colidem com dados anteriores, podemos escolher outra nova função de hash, de modo que, após a revisão, todos os dados anteriores que ele e todos os outros nos forneceram agora possam ser visualizados em 2 ou 3 sondas no pior caso - ou seja, O (1) pesquisas no pior caso.
É bastante fácil selecionar aleatoriamente uma nova função de hash e repetir toda a tabela com frequência suficiente para garantir que cada pesquisa seja sempre O (1). Embora isso garanta que cada pesquisa seja sempre O (1), essas técnicas, ao inserir o item N em uma tabela de hash que já contém itens N-1, ocasionalmente podem exigir tempo O (N) para essa inserção. No entanto, é possível projetar o sistema de forma que, mesmo quando Mallory deliberadamente forneça novos dados que, usando a nova função hash, colidem com dados anteriores, o sistema possa aceitar muitos itens de Mallory e outros antes de precisar fazer uma reconstrução total de O (N). As técnicas de tabela de hash que selecionam uma nova função e refazer a tarefa para garantir O (1) pesquisas, mesmo no pior caso, incluem:
- O cuckoo hashing garante que cada pesquisa de chave seja bem-sucedida com no máximo 2 cálculos de hash e 2 pesquisas de tabela.
- O hashing de amarelinha garante que cada pesquisa de chave seja bem-sucedida após a inspeção no pequeno número H (talvez H = 32) de entradas consecutivas na tabela.
- hashing perfeito dinâmico - o artigo de 1994 de Dietzfelbinger é o primeiro que li que apontou que, embora seja repetido "com frequência" para garantir que cada pesquisa-chave sempre tenha sucesso com 2 cálculos de hash e 2 pesquisas, é possível para realizar uma revisão completa tão raramente que, embora cada revisão completa use O (n) tempo, o custo médio esperado de inserções e exclusões é O (1) amortizado.
Estruturas de dados / tabelas de hash