HashSet vs LinkedHashSet

153

Qual a diferença entre eles? Eu sei disso

Um LinkedHashSet é uma versão ordenada do HashSet que mantém uma lista duplamente vinculada em todos os elementos. Use esta classe em vez do HashSet quando se importar com a ordem da iteração. Quando você repete um HashSet, o pedido é imprevisível, enquanto um LinkedHashSet permite que você repita os elementos na ordem em que foram inseridos.

Mas no código-fonte do LinkedHashSet, existem apenas os construtores de chamada do HashSet. Então, onde estão os pedidos de lista e inserção com link duplo?

Shikarn-O
fonte
2
use a opção Intellij (Ctrl + B) para rastrear a resposta. :)
Delta
é claro que você precisa anexar o código-fonte. :)
Delta

Respostas:

65

A resposta está em que construtores os LinkedHashSetusos para construir a classe base:

public LinkedHashSet(int initialCapacity, float loadFactor) {
    super(initialCapacity, loadFactor, true);      // <-- boolean dummy argument
}

...

public LinkedHashSet(int initialCapacity) {
    super(initialCapacity, .75f, true);            // <-- boolean dummy argument
}

...

public LinkedHashSet() {
    super(16, .75f, true);                         // <-- boolean dummy argument
}

...

public LinkedHashSet(Collection<? extends E> c) {
    super(Math.max(2*c.size(), 11), .75f, true);   // <-- boolean dummy argument
    addAll(c);
}

E (um exemplo de) um HashSetconstrutor que aceita um argumento booleano é descrito e tem a seguinte aparência:

/**
 * Constructs a new, empty linked hash set.  (This package private
 * constructor is only used by LinkedHashSet.) The backing
 * HashMap instance is a LinkedHashMap with the specified initial
 * capacity and the specified load factor.
 *
 * @param      initialCapacity   the initial capacity of the hash map
 * @param      loadFactor        the load factor of the hash map
 * @param      dummy             ignored (distinguishes this
 *             constructor from other int, float constructor.)
 * @throws     IllegalArgumentException if the initial capacity is less
 *             than zero, or if the load factor is nonpositive
 */
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}
aioobe
fonte
2
A classe pai ter funcionalidade explicitamente para uma classe criança, um argumento ignorado distinguir
Traubenfuchs
5
Não é exatamente um design limpo, usando um parâmetro fictício para desambiguação do construtor.
Eric J.
8
O design é razoavelmente limpo, porque a API é limpa (esse construtor HashSet é um pacote privado). Os detalhes da implementação não importam para os usuários da classe. Manter esse código pode ser mais difícil, mas no caso das classes java.util, mesmo pequenas melhorias no desempenho podem justificar isso.
Lbalazscs 01/11/2015
25

LinkedHashSetOs construtores de invocam o seguinte construtor de classe base:

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
  map = new LinkedHashMap<E, Object>(initialCapacity, loadFactor);
}

Como você pode ver, o mapa interno é a LinkedHashMap. Se você olhar para dentro LinkedHashMap, descobrirá o seguinte campo:

private transient Entry<K, V> header;

Esta é a lista vinculada em questão.

NPE
fonte
24

HashSet é um conjunto não ordenado e não classificado .
LinkedHashSet é a versão ordenada do HashSet.

A única diferença entre HashSet e LinkedHashSet é que:
LinkedHashSet mantém a ordem de inserção.

Quando iteramos através de um HashSet , a ordem é imprevisível enquanto previsível no caso de LinkedHashSet .

A razão pela qual o LinkedHashSet mantém a ordem de inserção é o seguinte:
A estrutura de dados subjacente usada é a lista vinculada duplamente .

Hema Ganapathy
fonte
9

Você deve olhar para a fonte do HashSetconstrutor que ele chama ... é um construtor especial que torna o apoio Mapum em LinkedHashMapvez de apenas um HashMap.

ColinD
fonte
Graças, em HashSet há construtor para criar LinkedHashMap, que é chamado em LinkedHashSet e toda a lógica está em LinkedHashMap
Shikarn-O
5

Sugiro que você use a LinkedHashSetmaior parte do tempo, porque ele tem melhor desempenho geral ):

  1. Ordem de iteração previsível LinkedHashSet (Oracle)
  2. O LinkedHashSet é mais caro para inserções do que o HashSet;
  3. Em geral, desempenho um pouco melhor que HashMap, porque na maioria das vezes usamos estruturas Set para iteração.

Testes de performance:

------------- TreeSet -------------
 size       add  contains   iterate
   10       746       173        89
  100       501       264        68
 1000       714       410        69
10000      1975       552        69
------------- HashSet -------------
 size       add  contains   iterate
   10       308        91        94
  100       178        75        73
 1000       216       110        72
10000       711       215       100
---------- LinkedHashSet ----------
 size       add  contains   iterate
   10       350        65        83
  100       270        74        55
 1000       303       111        54
10000      1615       256        58

Você pode ver a página de teste de origem aqui: O Exemplo de Teste de Desempenho Final

Dmytro Melnychuk
fonte
2
Não vejo nenhum aquecimento da JVM antes desses "benchmarks", portanto não levaria esses dados a sério. Leia mais
Felix S
3

HashSet: Não ordenado, na verdade. se você passar o parâmetro significa

Set<Integer> set=new HashSet<Integer>();
for(int i=0;i<set.length;i++)
{
  SOP(set)`enter code here`
}

Saída: Pode 2,1,3não ser previsível. próxima vez que outro pedido.

LinkedHashSet() que produzem ordem FIFO.

Justin
fonte
3

HashSet não mantenha a ordem do item de inserção
LinkedHashSet mantenha a ordem do item de inserção

Exemplo

Set<String> set = ...;// using new HashSet<>() OR new LinkedHashSet<>()
set.add("2");
set.add("1");
set.add("ab");
for(String value : set){
   System.out.println(value);
}  

HashSet resultado

1
ab
2

LinkedHashSet resultado

2
1
ab
Phan Van Linh
fonte
2

HashSet:

A estrutura de dados sublinhada é Hashtable. Objetos duplicados não são permitidos. A ordem de inserção não é preservada e é baseada no código hash dos objetos. A inserção nula é possível (apenas uma vez). Ele implementa a interface Serializable, Clonable, mas não RandomAccess. O HashSet é a melhor opção se a operação frequente for a pesquisa.

No HashSet, duplicatas não são permitidas. Se os usuários estiverem tentando inserir duplicatas quando não recebermos nenhuma exceção de compilação ou tempo de execução. O método add retorna simplesmente falso.

Construtores:

HashSet h = novo HashSet (); cria um objeto HashSet vazio com capacidade inicial padrão 16 e a taxa de preenchimento padrão (fator de carga) é 0,75.

HashSet h = new HashSet (int initialCapacity); cria um objeto HashSet vazio com initialCapacity especificado e a taxa de preenchimento padrão é 0,75.

HashSet h = new HashSet (int initialCapacity, float fillRatio);

HashSet h = novo HashSet (Coleção c); cria um objeto HashSet equivalente para a coleção fornecida. Esse construtor é destinado à conversão entre objetos de coleção.

LinkedHashSet:

É uma classe filho do HashSet. é exatamente o mesmo que o HashSet, incluindo (Construtores e Métodos), exceto as seguintes diferenças.

Diferenças HashSet:

  1. A estrutura de dados sublinhada é Hashtable.
  2. O pedido de inserção não é preservado.
  3. introduziu a versão 1.2.

LinkedHashSet:

  1. A estrutura de dados sublinhada é uma combinação de LinkedList e Hashtable.
  2. O pedido de inserção é preservado.
  3. Indroduzido na versão 1.4.
Umapathi
fonte
1

Se você der uma olhada nos construtores chamados da LinkedHashSetclasse, verá que internamente LinkedHashMapé usado para fins de backup.

recife
fonte
0

Todos os métodos e construtores são iguais, mas apenas uma diferença é que o LinkedHashset manterá a ordem de inserção, mas não permitirá duplicatas.

O Hashset não manterá nenhum pedido de inserção. É uma combinação de lista e conjunto simples :)

Anand Mohan
fonte