Ao implementar um dicionário ('Desejo procurar dados do cliente por seus IDs de cliente'), as estruturas de dados típicas usadas são tabelas de hash e árvores de pesquisa binária. Eu sei, por exemplo, que a biblioteca C ++ STL implementa dicionários (eles os chamam de mapas) usando árvores de pesquisa binária (balanceadas) e o .NET framework usa tabelas de hash sob o capô.
Quais são as vantagens e desvantagens dessas estruturas de dados? Existe alguma outra opção razoável em determinadas situações?
Observe que não estou particularmente interessado nos casos em que as chaves têm uma estrutura subjacente forte, digamos, são todos números inteiros entre 1 e n ou algo assim.
algorithms
data-structures
binary-trees
hash-tables
Alex ten Brink
fonte
fonte
Respostas:
A resposta curta é que as tabelas de hash são mais rápidas na maioria dos casos , mas podem ser muito ruins na pior das hipóteses. As árvores de pesquisa têm muitas vantagens, incluindo o pior comportamento , mas são um pouco mais lentas em casos típicos.
Quando você coloca a localidade dos dados na mistura, as tabelas de hash se saem mal. Eles funcionam precisamente porque armazenam elementos relacionados distantes, o que significa que, se o aplicativo procurar elementos que compartilham um prefixo em sequência, ele não se beneficiará dos efeitos do cache. Isso não é relevante se o aplicativo fizer pesquisas essencialmente aleatórias.
Outro fator a favor das árvores de pesquisa é que elas são uma estrutura de dados imutável : se você precisar fazer uma cópia de uma árvore e alterar alguns elementos nela, poderá compartilhar a maior parte da estrutura de dados. Se você tirar uma cópia de uma tabela de hash, precisará copiar toda a matriz de ponteiros. Além disso, se você estiver trabalhando em uma linguagem puramente funcional, as tabelas de hash geralmente não são uma opção.
Em particular, se você precisar da ordem das teclas, por exemplo, se quiser listar as chaves em ordem alfabética, as tabelas de hash não ajudarão (você precisará classificá-las), enquanto você pode atravessar diretamente uma árvore de pesquisa em ordem.
Você pode combinar árvores de pesquisa binária e tabelas de hash na forma de árvores de hash . Uma árvore de hash armazena chaves em uma árvore de pesquisa de acordo com seu hash. Isso é útil, por exemplo, em uma linguagem de programação puramente funcional na qual você deseja trabalhar com dados que não possuem uma relação de ordem fácil de calcular.
Quando as chaves são cadeias (ou números inteiros), um trie pode ser outra opção. Um trie é uma árvore, mas indexado de forma diferente de uma árvore de pesquisa: você escreve a chave em binário e sai à esquerda para 0 e à direita para 1. 1. O custo de um acesso é, portanto, proporcional ao comprimento da chave. As tentativas podem ser compactadas para remover nós intermediários; isso é conhecido como uma árvore patricia trie ou radix . As árvores Radix podem superar as árvores equilibradas, principalmente quando muitas chaves compartilham um prefixo comum.
fonte