Ouvi em minhas aulas de graduação que a HashTable
colocará uma nova entrada no bloco 'próximo disponível' se a nova entrada de chave colidir com outra.
Como o HashTable
ainda retornaria o valor correto se essa colisão ocorrer ao chamar alguém de volta com a chave de colisão?
Estou assumindo que o tipo Keys
are String
e hashCode()
retorna o padrão gerado por, digamos, Java.
Se eu implementar minha própria função de hashing e usá-la como parte de uma tabela de consulta (ou seja, a HashMap
ou Dictionary
), quais estratégias existem para lidar com colisões?
Eu até vi notas relacionadas a números primos! Informações não tão claras na pesquisa do Google.
Quando você falou sobre "A tabela de hash colocará uma nova entrada no depósito 'próximo disponível' se a nova entrada de chave colidir com outra.", Você está falando sobre a estratégia de endereçamento aberto de resolução de colisão da tabela de hash.
Existem várias estratégias para a tabela de hash resolver a colisão.
O primeiro tipo de método grande exige que as chaves (ou ponteiros para elas) sejam armazenadas na tabela, junto com os valores associados, que incluem ainda:
Outro método importante para lidar com a colisão é por redimensionamento dinâmico , que ainda tem várias maneiras:
EDITAR : os itens acima foram emprestados de wiki_hash_table , onde você deve dar uma olhada para obter mais informações.
fonte
Existem várias técnicas disponíveis para lidar com a colisão. Vou explicar alguns deles
Encadeamento: no encadeamento, usamos índices de array para armazenar os valores. Se o código hash do segundo valor também aponta para o mesmo índice, então substituímos esse valor de índice por uma lista encadeada e todos os valores que apontam para esse índice são armazenados na lista encadeada e o índice de array real aponta para o início da lista encadeada. Mas se houver apenas um código hash apontando para um índice de array, o valor é armazenado diretamente nesse índice. A mesma lógica é aplicada ao recuperar os valores. Isso é usado em Java HashMap / Hashtable para evitar colisões.
Sondagem linear: esta técnica é usada quando temos mais índice na tabela do que os valores a serem armazenados. A técnica de sondagem linear funciona com o conceito de continuar incrementando até encontrar um slot vazio. O pseudocódigo tem a seguinte aparência:
Técnica de hash duplo: nesta técnica, usamos duas funções de hash h1 (k) e h2 (k). Se o slot em h1 (k) estiver ocupado, a segunda função de hashing h2 (k) usada para incrementar o índice. O pseudocódigo tem a seguinte aparência:
As técnicas de sondagem linear e hashing duplo fazem parte da técnica de endereçamento aberto e só podem ser usadas se os slots disponíveis forem mais do que o número de itens a serem adicionados. Leva menos memória do que o encadeamento porque não há nenhuma estrutura extra usada aqui, mas é lento porque muitos movimentos acontecem até encontrarmos um slot vazio. Também na técnica de endereçamento aberto, quando um item é removido de um slot, colocamos uma marca de exclusão para indicar que o item foi removido daqui, por isso está vazio.
Para obter mais informações, consulte este site .
fonte
Eu sugiro fortemente que você leia esta postagem do blog que apareceu no HackerNews recentemente: Como o HashMap funciona em Java
Em suma, a resposta é
fonte
Na verdade, isso não é verdade, pelo menos para o Oracle JDK ( é um detalhe de implementação que pode variar entre as diferentes implementações da API). Em vez disso, cada depósito contém uma lista vinculada de entradas anteriores ao Java 8 e uma árvore balanceada no Java 8 ou superior.
Ele usa o
equals()
para encontrar a entrada realmente correspondente.Existem várias estratégias de tratamento de colisões com diferentes vantagens e desvantagens. A entrada da Wikipedia em tabelas de hash oferece uma boa visão geral.
fonte
Hashtable
eHashMap
no JDK 1.6.0_22 da Sun / Oracle.public V get(Object key)
agora (mesma versão acima). Se você encontrar uma versão precisa onde essas listas vinculadas aparecem, eu gostaria de saber.Entry
objetos:localEntry = localEntry.next
e = e.next
não é++index
. +1Atualização desde Java 8: Java 8 usa uma árvore auto-balanceada para tratamento de colisão, melhorando o pior caso de O (n) para O (log n) para pesquisa. O uso de uma árvore auto-balanceada foi introduzido no Java 8 como uma melhoria sobre o encadeamento (usado até o java 7), que usa uma lista vinculada e tem um pior caso de O (n) para pesquisa (uma vez que precisa atravessar a lista)
Para responder à segunda parte da sua pergunta, a inserção é feita mapeando um determinado elemento para um determinado índice na matriz subjacente do hashmap, no entanto, quando ocorre uma colisão, todos os elementos ainda devem ser preservados (armazenados em uma estrutura de dados secundária , e não apenas substituído na matriz subjacente). Isso geralmente é feito fazendo com que cada componente da matriz (slot) seja uma estrutura de dados secundária (também conhecido como balde), e o elemento é adicionado ao depósito que reside no índice de matriz fornecido (se a chave ainda não existir no depósito, em caso em que é substituído).
Durante a pesquisa, a chave é hash para seu índice de matriz correspondente, e a pesquisa é realizada por um elemento que corresponda à chave (exata) no intervalo fornecido. Como o balde não precisa lidar com colisões (compara as chaves diretamente), isso resolve o problema das colisões, mas o faz ao custo de ter que realizar a inserção e consulta na estrutura de dados secundária. O ponto principal é que em um hashmap, a chave e o valor são armazenados e, portanto, mesmo se o hash colidir, as chaves são comparadas diretamente quanto à igualdade (no balde) e, portanto, podem ser identificadas exclusivamente no balde.
Tratamento de colisão traz o pior caso de desempenho de inserção e pesquisa de O (1) no caso de não tratamento de colisão para O (n) para encadeamento (uma lista vinculada é usada como estrutura de dados secundária) e O (log n) para árvore auto-equilibrada.
Referências:
fonte
Ele usará o método equals para ver se a chave está presente mesmo e, especialmente, se houver mais de um elemento no mesmo intervalo.
fonte
Como há alguma confusão sobre qual algoritmo o HashMap do Java está usando (na implementação Sun / Oracle / OpenJDK), aqui estão os trechos de código-fonte relevantes (do OpenJDK, 1.6.0_20, no Ubuntu):
Este método (cite é das linhas 355 a 371) é chamado ao pesquisar uma entrada na tabela, por exemplo
get()
, fromcontainsKey()
e alguns outros. O loop for aqui passa pela lista encadeada formada pelos objetos de entrada.Aqui está o código para os objetos de entrada (linhas 691-705 + 759):
Logo em seguida vem o
addEntry()
método:Isso adiciona a nova entrada na frente do depósito, com um link para a primeira entrada antiga (ou nulo, se não houver). Da mesma forma, o
removeEntryForKey()
método percorre a lista e se encarrega de excluir apenas uma entrada, deixando o resto da lista intacto.Então, aqui está uma lista de entrada vinculada para cada segmento e duvido muito que isso tenha mudado de
_20
para_22
, já que foi assim a partir de 1.2.(Este código é (c) 1997-2007 Sun Microsystems, e disponível sob GPL, mas para copiar melhor use o arquivo original, contido em src.zip em cada JDK da Sun / Oracle, e também no OpenJDK.)
fonte
aqui está uma implementação de tabela hash muito simples em java. em apenas implementos
put()
eget()
, mas você pode adicionar facilmente o que quiser. ele depende dohashCode()
método java que é implementado por todos os objetos. você pode facilmente criar sua própria interface,e force sua implementação pelas chaves, se desejar.
fonte
Existem vários métodos para resolução de colisão. Alguns deles são encadeamento separado, endereçamento aberto, hashing Robin Hood, hashing cuco etc.
Java usa o encadeamento separado para resolver colisões em tabelas de Hash. Este é um ótimo link para saber como isso acontece: http://javapapers.com/core-java/java-hashtable/
fonte