Desejo implementar uma tabela de hash usando árvores de pesquisa binária para reduzir a complexidade da pesquisa no processo de encadeamento separado de O (n) (usando lista vinculada) a O (log n) (usando BST). Isso pode ser feito e, se sim, como? Seria mais fácil entender se a solução é passo a passo, implementação da lógica.
Desejo reduzir o tempo de pesquisa na hashtable (compilação usando encadeamento separado), mas, ao mesmo tempo, não quero que o tempo de inserção aumente. Para o meu projeto, não posso alterar a função hash para reduzir colisões. Mas, devido à escalabilidade, colisões estão acontecendo. Estou tentando encontrar uma solução alternativa para que, de alguma forma, eu possa trabalhar com o melhor acesso e inserir tempo no caso de uma colisão ... ou seja, para gerenciar o estado atual das coisas do que para reestruturar todo o algoritmo. Se não der certo, terá que se reestruturar. Então, alguma idéia?
Respostas:
O que você está pedindo é possível, dadas as suas restrições.
Análise
A força de uma tabela de hash é sua rápida pesquisa e velocidade de inserção. Para obter essa velocidade, é preciso abandonar qualquer aparência de ordem na tabela: ou seja, as entradas são todas desordenadas. Uma lista é aceitável para uso como entrada da tabela porque, embora a travessia seja O (n), as listas tendem a ser curtas, supondo que a tabela de hash seja suficientemente grande e que os objetos armazenados na tabela sejam hash usando um algoritmo de hash de boa qualidade.
Uma árvore de pesquisa binária (BST) tem inserção e pesquisa rápidas em O (log 2 n). Também impõe uma restrição aos elementos que armazena: deve haver alguma maneira de ordenar os elementos. Dados dois elementos A e B armazenados na árvore, deve ser possível determinar se A vem antes de B ou se eles têm ordem equivalente.
Uma tabela de hash não impõe essa restrição: os elementos em uma tabela de hash devem ter duas propriedades. Primeiro, deve haver uma maneira de determinar se são equivalentes; segundo, deve haver uma maneira de calcular um código hash determinístico. A ordem não é um requisito.
Se seus elementos da tabela de hash tiverem um pedido, você poderá usar uma BST como uma entrada da tabela de hash para manter objetos com o mesmo código de hash (colisões). No entanto, devido a uma BST ter pesquisa e inserção de O (log 2 n), isso significa que o pior caso para toda a estrutura (tabela de hash mais BST) é tecnicamente melhor do que usar uma lista como entrada da tabela. Dependendo da implementação do BST, será necessário mais armazenamento do que uma lista, mas provavelmente não muito mais.
Observe que normalmente a sobrecarga e o comportamento de um BST não traz nada para a tabela em situações do mundo real como baldes de tabelas de hash, e é por isso que o baixo desempenho teórico de uma lista é aceitável. Em outras palavras, a tabela de hash compensa a fraqueza da lista, colocando menos itens em cada lista (bloco). No entanto : o problema declarou especificamente que a tabela de hash não pode aumentar de tamanho e as colisões são mais frequentes do que o normal em uma tabela de hash.
Implementação
Não vou colocar código aqui, porque honestamente não é realmente necessário e você não forneceu um idioma de qualquer maneira.
O que eu faria é simplesmente copiar qualquer tabela de hash padrão que a biblioteca padrão de seu idioma contenha em uma nova classe e alterar o tipo de balde de tabela de uma lista para uma árvore. Dependendo do idioma e de sua biblioteca padrão, isso pode ser algo muito trivial.
Normalmente, eu não recomendaria copiar e colar códigos como este. No entanto, é uma maneira fácil de obter uma estrutura de dados testada em batalha muito rapidamente.
fonte
Usar uma árvore binária para lidar com colisões em uma tabela de hash não é apenas possível - foi feito.
Walter Bright é mais conhecido como o inventor da linguagem de programação D , mas também escreveu uma variante ECMAScript chamada DMDScript . No passado, uma reivindicação principal do DMDScript (ou possivelmente um ancestral - parece que me lembro do nome DScript) era que suas hashtables tendiam a superar as de muitas linguagens semelhantes. O motivo - tratamento de colisão usando árvores binárias.
Não me lembro exatamente de onde é isso, mas as árvores usadas eram binárias ingênuas, sem um esquema de equilíbrio parcial (não AVL, preto-vermelho ou qualquer outra coisa), o que faz sentido, assumindo que a própria hashtable é redimensionada quando fica cheia demais e você não obtém taxas absurdamente improváveis de colisões de hash, as árvores binárias devem sempre ser pequenas. Basicamente, o pior caso ainda é o mesmo que usar uma lista vinculada para tratamento de colisão (exceto que você paga o preço de dois ponteiros por nó em vez de um), mas o caso médio reduz a quantidade de pesquisa em cada intervalo de hash.
fonte