Desempenho HashSet vs. Lista

406

É claro que um desempenho de pesquisa da HashSet<T>classe genérica é maior que o da List<T>classe genérica . Basta comparar a chave baseada em hash com a abordagem linear na List<T>classe.

No entanto, o cálculo de uma chave de hash pode levar alguns ciclos de CPU, portanto, para uma pequena quantidade de itens, a pesquisa linear pode ser uma alternativa real à HashSet<T>.

Minha pergunta: onde está o ponto de equilíbrio?

Para simplificar o cenário (e para ser justo), vamos supor que a List<T>classe use o Equals()método do elemento para identificar um item.

Michael Damatov
fonte
7
Se você realmente deseja minimizar o tempo de pesquisa, considere também matrizes e matrizes ordenadas. Para responder adequadamente a essa pergunta, é necessário um benchmark, mas você precisa nos contar mais sobre T. Além disso, o desempenho do HashSet pode ser afetado pelo tempo de execução de T.GetHashCode ().
precisa saber é o seguinte

Respostas:

819

Muitas pessoas estão dizendo que quando você chega ao tamanho em que a velocidade é realmente uma preocupação que HashSet<T>sempre supera List<T>, mas isso depende do que você está fazendo.

Digamos que você tenha um List<T>que só terá em média 5 itens. Durante um grande número de ciclos, se um único item for adicionado ou removido a cada ciclo, é melhor usar a List<T>.

Fiz um teste para isso na minha máquina e, bem, tem que ser muito pequeno para obter vantagem List<T>. Para uma lista de cadeias curtas, a vantagem desapareceu após o tamanho 5, para objetos após o tamanho 20.

1 item LIST strs time: 617ms
1 item HASHSET strs time: 1332ms

2 item LIST strs time: 781ms
2 item HASHSET strs time: 1354ms

3 item LIST strs time: 950ms
3 item HASHSET strs time: 1405ms

4 item LIST strs time: 1126ms
4 item HASHSET strs time: 1441ms

5 item LIST strs time: 1370ms
5 item HASHSET strs time: 1452ms

6 item LIST strs time: 1481ms
6 item HASHSET strs time: 1418ms

7 item LIST strs time: 1581ms
7 item HASHSET strs time: 1464ms

8 item LIST strs time: 1726ms
8 item HASHSET strs time: 1398ms

9 item LIST strs time: 1901ms
9 item HASHSET strs time: 1433ms

1 item LIST objs time: 614ms
1 item HASHSET objs time: 1993ms

4 item LIST objs time: 837ms
4 item HASHSET objs time: 1914ms

7 item LIST objs time: 1070ms
7 item HASHSET objs time: 1900ms

10 item LIST objs time: 1267ms
10 item HASHSET objs time: 1904ms

13 item LIST objs time: 1494ms
13 item HASHSET objs time: 1893ms

16 item LIST objs time: 1695ms
16 item HASHSET objs time: 1879ms

19 item LIST objs time: 1902ms
19 item HASHSET objs time: 1950ms

22 item LIST objs time: 2136ms
22 item HASHSET objs time: 1893ms

25 item LIST objs time: 2357ms
25 item HASHSET objs time: 1826ms

28 item LIST objs time: 2555ms
28 item HASHSET objs time: 1865ms

31 item LIST objs time: 2755ms
31 item HASHSET objs time: 1963ms

34 item LIST objs time: 3025ms
34 item HASHSET objs time: 1874ms

37 item LIST objs time: 3195ms
37 item HASHSET objs time: 1958ms

40 item LIST objs time: 3401ms
40 item HASHSET objs time: 1855ms

43 item LIST objs time: 3618ms
43 item HASHSET objs time: 1869ms

46 item LIST objs time: 3883ms
46 item HASHSET objs time: 2046ms

49 item LIST objs time: 4218ms
49 item HASHSET objs time: 1873ms

Aqui estão os dados exibidos como um gráfico:

insira a descrição da imagem aqui

Aqui está o código:

static void Main(string[] args)
{
    int times = 10000000;


    for (int listSize = 1; listSize < 10; listSize++)
    {
        List<string> list = new List<string>();
        HashSet<string> hashset = new HashSet<string>();

        for (int i = 0; i < listSize; i++)
        {
            list.Add("string" + i.ToString());
            hashset.Add("string" + i.ToString());
        }

        Stopwatch timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < times; i++)
        {
            list.Remove("string0");
            list.Add("string0");
        }
        timer.Stop();
        Console.WriteLine(listSize.ToString() + " item LIST strs time: " + timer.ElapsedMilliseconds.ToString() + "ms");


        timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < times; i++)
        {
            hashset.Remove("string0");
            hashset.Add("string0");
        }
        timer.Stop();
        Console.WriteLine(listSize.ToString() + " item HASHSET strs time: " + timer.ElapsedMilliseconds.ToString() + "ms");
        Console.WriteLine();
    }


    for (int listSize = 1; listSize < 50; listSize+=3)
    {
        List<object> list = new List<object>();
        HashSet<object> hashset = new HashSet<object>();

        for (int i = 0; i < listSize; i++)
        {
            list.Add(new object());
            hashset.Add(new object());
        }

        object objToAddRem = list[0];

        Stopwatch timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < times; i++)
        {
            list.Remove(objToAddRem);
            list.Add(objToAddRem);
        }
        timer.Stop();
        Console.WriteLine(listSize.ToString() + " item LIST objs time: " + timer.ElapsedMilliseconds.ToString() + "ms");



        timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < times; i++)
        {
            hashset.Remove(objToAddRem);
            hashset.Add(objToAddRem);
        }
        timer.Stop();
        Console.WriteLine(listSize.ToString() + " item HASHSET objs time: " + timer.ElapsedMilliseconds.ToString() + "ms");
        Console.WriteLine();
    }

    Console.ReadLine();
}
innominate227
fonte
8
Muito obrigado! Essa é uma ótima explicação, eu estava procurando por algo que pudesse adicionar e remover mais rapidamente do que o List<T>de um mecanismo de jogo e, como normalmente terei um alto volume de objetos, esse tipo de coleção seria perfeito.
Redcodefinal
17
Na verdade, existe uma coleção na estrutura .NET que alterna entre uma lista e uma implementação apressada, dependendo do número de itens que ela contém: HybridDictionary .
amigos estão dizendo sobre mgsam
8
A Microsoft parece ter abandonado o que pensava, pois possui apenas uma versão não genérica disponível.
amigos estão dizendo sobre mgsam
47
Por mais completa que seja essa resposta, ela não responde à pergunta original sobre o desempenho da pesquisa de lista versus hashset. Você está testando a rapidez com que pode inserir e remover deles, o que leva consideravelmente mais tempo e características de desempenho diferentes do que a pesquisa. Tente novamente usando. Contém, e seu gráfico mudará significativamente.
9788 Robert McKee #
5
@hypehuman a CPU não pode trabalhar diretamente com os dados na memória do sistema, mas extrai os dados da memória para o cache para trabalhar. Há um atraso significativo entre a solicitação de memória a ser movida e a memória que está chegando, de modo que a CPU geralmente solicita que um pedaço maior de memória contígua seja movido de uma só vez. A idéia por trás disso é que a memória necessária para a próxima instrução provavelmente está muito próxima da memória usada pela instrução anterior e, portanto, muitas vezes já está no cache. Quando seus dados estão espalhados por toda a memória, a chance de ter sorte é reduzida.
Roy T.
70

Você está vendo isso errado. Sim, uma pesquisa linear de uma lista superará um HashSet para um pequeno número de itens. Mas a diferença de desempenho geralmente não importa para coleções tão pequenas. Geralmente, é com as grandes coleções que você precisa se preocupar, e é aí que você pensa em termos de Big-O . No entanto, se você tiver medido um gargalo real no desempenho do HashSet, poderá tentar criar um híbrido List / HashSet, mas fará isso realizando muitos testes de desempenho empíricos - sem fazer perguntas sobre o SO.

Eloff
fonte
5
grandes coleções com as quais você precisa se preocupar . Podemos redefinir essa pergunta em termos de when small collection becomes large enough to worry about HashSet vs List?dezenas, dezenas de milhares, bilhões de elementos?
Om-nom-nom
8
Não, você verá uma considerável diferença de desempenho acima de algumas centenas de elementos. O ponto é sempre usar um HashSet se você estiver fazendo os tipos de acesso nos quais o HashSet é bom (por exemplo, é o elemento X do conjunto.) Se sua coleção é tão pequena que uma Lista é mais rápida, é muito raro que essas pesquisas são realmente um gargalo no seu aplicativo. Se você pode medir para ser um, tudo bem, você pode tentar otimizá-lo - mas, caso contrário, você está perdendo seu tempo.
Eloff
15
E se você tiver uma pequena coleção que é atingida várias vezes em um loop? Esse não é um cenário incomum.
precisa
3
@ om-nom-nom - Acho que o ponto é que não importa onde está o ponto de inflexão, porque: "Se o desempenho for uma preocupação, use HashSet<T>. Nos casos de pequeno número em que List<T>pode ser mais rápido, a diferença é insignificante. . "
21715 Scott Scott
66

É essencialmente inútil comparar duas estruturas de desempenho que se comportam de maneira diferente. Use a estrutura que transmite a intenção. Mesmo se você disser List<T>que não teria duplicatas e a ordem de iteração não for comparável a a HashSet<T>, ainda é uma má escolha para usar, List<T>porque é relativamente menos tolerante a falhas.

Dito isto, vou inspecionar alguns outros aspectos do desempenho,

+------------+--------+-------------+-----------+----------+----------+-----------+
| Collection | Random | Containment | Insertion | Addition |  Removal | Memory    |
|            | access |             |           |          |          |           |
+------------+--------+-------------+-----------+----------+----------+-----------+
| List<T>    | O(1)   | O(n)        | O(n)      | O(1)*    | O(n)     | Lesser    |
| HashSet<T> | O(n)   | O(1)        | n/a       | O(1)     | O(1)     | Greater** |
+------------+--------+-------------+-----------+----------+----------+-----------+
  • Embora a adição seja O (1) nos dois casos, será relativamente mais lento no HashSet, pois envolve o custo da pré-computação do código hash antes de armazená-lo.

  • A escalabilidade superior do HashSet tem um custo de memória. Cada entrada é armazenada como um novo objeto, juntamente com seu código de hash. Este artigo pode lhe dar uma ideia.

nawfal
fonte
11
Minha pergunta (seis anos atrás) não era sobre o desempenho teórico .
Michael Damatov
11
HashSet permite acesso aleatório com ElementAt (), e acho que seria hora O (n). Além disso, talvez você possa colocar em sua tabela se cada coleção permite duplicatas (por exemplo: listas permitem, mas hashsets não).
Dan W
11
@ DanW na tabela Estou comparando desempenho puramente, não características comportamentais. Obrigado pela dica ElementAt.
Nawfal # 7/15
11
ElementAt é apenas uma extensão LINQ .. ele não faz nada que você não pode fazer e otimiza melhor em outro método que você adiciona. Eu acho que a tabela fez mais sentido sem considerar ElementAt, pois todos os outros métodos existem nessas classes explicitamente.
Dinerdo
11
Obrigado por esta tabela, no meu caso de uso, preciso adicionar e remover destinos de uma coleção preenchida toda vez que eles são ativados / desativados e isso me ajudou a fazer a escolha certa (HashSet).
Casey Hofland
50

A utilização de um HashSet <> ou Lista <> se resume a como você precisa acessar sua coleção . Se você precisar garantir a ordem dos itens, use uma Lista. Caso contrário, use um HashSet. Deixe a Microsoft se preocupar com a implementação de seus algoritmos e objetos de hash.

Um HashSet acessará itens sem precisar enumerar a coleção (complexidade de O (1) ou próximo a ela) e, como uma Lista garante ordem, diferentemente de um HashSet, alguns itens terão que ser enumerados (complexidade de O (n)).

testemunho
fonte
A lista potencialmente pode calcular o deslocamento para o elemento específico por seu índice (porque todos os elementos são do mesmo tipo e potencialmente ocupam o mesmo tamanho de memória). Então lista não é enumera necessários elementos de TI
Lu55
@ Lu55 - A pergunta é sobre procurar um item em uma coleção. Um cenário típico é que a coleção é dinâmica - os itens podem ter sido adicionados ou excluídos desde a última vez que você procurou um determinado item -, portanto, um índice não é significativo (porque será alterado). Se você possui uma coleção estática (que não muda durante a execução de seus cálculos) ou se os itens nunca são excluídos e sempre são adicionados ao final, então Listé preferível um, porque você pode se lembrar de um índice - essa é a situação em que você estão descrevendo.
Home
Você pode usar um SortedSet se precisar classificar um HashSet. Ainda muito mais rápido que uma lista.
live-love
25

Apenas pensei em usar algumas referências para diferentes cenários para ilustrar as respostas anteriores:

  1. Algumas (12 - 20) seqüências pequenas (comprimento entre 5 e 10 caracteres)
  2. Muitas (~ 10K) cordas pequenas
  3. Algumas seqüências longas (comprimento entre 200 e 1000 caracteres)
  4. Muitas strings longas (~ 5K)
  5. Alguns números inteiros
  6. Muitos números inteiros (~ 10K)

E para cada cenário, procurando valores que aparecem:

  1. No início da lista ("start", índice 0)
  2. Perto do início da lista ("precoce", índice 1)
  3. No meio da lista ("meio", contagem de índices / 2)
  4. Perto do final da lista ("atrasado", contagem de índices 2)
  5. No final da lista ("final", contagem de índices 1)

Antes de cada cenário, eu gerava listas de seqüências aleatórias de tamanho aleatório e depois alimentava cada lista com um hashset. Cada cenário foi executado 10.000 vezes, essencialmente:

(pseudocódigo de teste)

stopwatch.start
for X times
    exists = list.Contains(lookup);
stopwatch.stop

stopwatch.start
for X times
    exists = hashset.Contains(lookup);
stopwatch.stop

Saída de amostra

Testado no Windows 7, 12 GB de RAM, 64 bits, Xeon 2,8 GHz

---------- Testing few small strings ------------
Sample items: (16 total)
vgnwaloqf diwfpxbv tdcdc grfch icsjwk
...

Benchmarks:
1: hashset: late -- 100.00 % -- [Elapsed: 0.0018398 sec]
2: hashset: middle -- 104.19 % -- [Elapsed: 0.0019169 sec]
3: hashset: end -- 108.21 % -- [Elapsed: 0.0019908 sec]
4: list: early -- 144.62 % -- [Elapsed: 0.0026607 sec]
5: hashset: start -- 174.32 % -- [Elapsed: 0.0032071 sec]
6: list: middle -- 187.72 % -- [Elapsed: 0.0034536 sec]
7: list: late -- 192.66 % -- [Elapsed: 0.0035446 sec]
8: list: end -- 215.42 % -- [Elapsed: 0.0039633 sec]
9: hashset: early -- 217.95 % -- [Elapsed: 0.0040098 sec]
10: list: start -- 576.55 % -- [Elapsed: 0.0106073 sec]


---------- Testing many small strings ------------
Sample items: (10346 total)
dmnowa yshtrxorj vthjk okrxegip vwpoltck
...

Benchmarks:
1: hashset: end -- 100.00 % -- [Elapsed: 0.0017443 sec]
2: hashset: late -- 102.91 % -- [Elapsed: 0.0017951 sec]
3: hashset: middle -- 106.23 % -- [Elapsed: 0.0018529 sec]
4: list: early -- 107.49 % -- [Elapsed: 0.0018749 sec]
5: list: start -- 126.23 % -- [Elapsed: 0.0022018 sec]
6: hashset: early -- 134.11 % -- [Elapsed: 0.0023393 sec]
7: hashset: start -- 372.09 % -- [Elapsed: 0.0064903 sec]
8: list: middle -- 48,593.79 % -- [Elapsed: 0.8476214 sec]
9: list: end -- 99,020.73 % -- [Elapsed: 1.7272186 sec]
10: list: late -- 99,089.36 % -- [Elapsed: 1.7284155 sec]


---------- Testing few long strings ------------
Sample items: (19 total)
hidfymjyjtffcjmlcaoivbylakmqgoiowbgxpyhnrreodxyleehkhsofjqenyrrtlphbcnvdrbqdvji...
...

Benchmarks:
1: list: early -- 100.00 % -- [Elapsed: 0.0018266 sec]
2: list: start -- 115.76 % -- [Elapsed: 0.0021144 sec]
3: list: middle -- 143.44 % -- [Elapsed: 0.0026201 sec]
4: list: late -- 190.05 % -- [Elapsed: 0.0034715 sec]
5: list: end -- 193.78 % -- [Elapsed: 0.0035395 sec]
6: hashset: early -- 215.00 % -- [Elapsed: 0.0039271 sec]
7: hashset: end -- 248.47 % -- [Elapsed: 0.0045386 sec]
8: hashset: start -- 298.04 % -- [Elapsed: 0.005444 sec]
9: hashset: middle -- 325.63 % -- [Elapsed: 0.005948 sec]
10: hashset: late -- 431.62 % -- [Elapsed: 0.0078839 sec]


---------- Testing many long strings ------------
Sample items: (5000 total)
yrpjccgxjbketcpmnvyqvghhlnjblhgimybdygumtijtrwaromwrajlsjhxoselbucqualmhbmwnvnpnm
...

Benchmarks:
1: list: early -- 100.00 % -- [Elapsed: 0.0016211 sec]
2: list: start -- 132.73 % -- [Elapsed: 0.0021517 sec]
3: hashset: start -- 231.26 % -- [Elapsed: 0.003749 sec]
4: hashset: end -- 368.74 % -- [Elapsed: 0.0059776 sec]
5: hashset: middle -- 385.50 % -- [Elapsed: 0.0062493 sec]
6: hashset: late -- 406.23 % -- [Elapsed: 0.0065854 sec]
7: hashset: early -- 421.34 % -- [Elapsed: 0.0068304 sec]
8: list: middle -- 18,619.12 % -- [Elapsed: 0.3018345 sec]
9: list: end -- 40,942.82 % -- [Elapsed: 0.663724 sec]
10: list: late -- 41,188.19 % -- [Elapsed: 0.6677017 sec]


---------- Testing few ints ------------
Sample items: (16 total)
7266092 60668895 159021363 216428460 28007724
...

Benchmarks:
1: hashset: early -- 100.00 % -- [Elapsed: 0.0016211 sec]
2: hashset: end -- 100.45 % -- [Elapsed: 0.0016284 sec]
3: list: early -- 101.83 % -- [Elapsed: 0.0016507 sec]
4: hashset: late -- 108.95 % -- [Elapsed: 0.0017662 sec]
5: hashset: middle -- 112.29 % -- [Elapsed: 0.0018204 sec]
6: hashset: start -- 120.33 % -- [Elapsed: 0.0019506 sec]
7: list: late -- 134.45 % -- [Elapsed: 0.0021795 sec]
8: list: start -- 136.43 % -- [Elapsed: 0.0022117 sec]
9: list: end -- 169.77 % -- [Elapsed: 0.0027522 sec]
10: list: middle -- 237.94 % -- [Elapsed: 0.0038573 sec]


---------- Testing many ints ------------
Sample items: (10357 total)
370826556 569127161 101235820 792075135 270823009
...

Benchmarks:
1: list: early -- 100.00 % -- [Elapsed: 0.0015132 sec]
2: hashset: end -- 101.79 % -- [Elapsed: 0.0015403 sec]
3: hashset: early -- 102.08 % -- [Elapsed: 0.0015446 sec]
4: hashset: middle -- 103.21 % -- [Elapsed: 0.0015618 sec]
5: hashset: late -- 104.26 % -- [Elapsed: 0.0015776 sec]
6: list: start -- 126.78 % -- [Elapsed: 0.0019184 sec]
7: hashset: start -- 130.91 % -- [Elapsed: 0.0019809 sec]
8: list: middle -- 16,497.89 % -- [Elapsed: 0.2496461 sec]
9: list: end -- 32,715.52 % -- [Elapsed: 0.4950512 sec]
10: list: late -- 33,698.87 % -- [Elapsed: 0.5099313 sec]
drzaus
fonte
7
Interessante. Obrigado por executar isso. Infelizmente, suspeito que essas discussões desencadeiam refatorações desnecessárias. Esperamos que o principal argumento para a maioria das pessoas seja que, no pior cenário possível, Listainda leve apenas 0,17 milissegundos para executar uma única pesquisa e provavelmente não será necessário substituir HashSetaté que a frequência de pesquisa atinja níveis absurdos. Até então, o uso da lista geralmente é o menor dos problemas.
Paul Walls
Esta não é uma informação real por enquanto .. Ou talvez esteja originalmente errada ... Acabei de verificar pequenos valores de 2 a 8 caracteres. List / HashSet foram criados para cada 10 valores ... HashSet mais lento para 30% ... Se a capacidade da Lista for usada, a diferença será de aproximadamente 40%. O HashSet se torna mais rápido em 10% apenas se Listarmos sem capacidade especificada e verificarmos cada valor antes de adicionar toda a lista.
Maxim
Se a contagem de itens for reduzida para 4, a Lista novamente vence mesmo no pior cenário (com 10% de diferença). Portanto, não recomendo usar o HashSet para pequenas coleções de strings (digamos <20). E é o que é diferente dos seus "poucos testes pequenos".
Maxim
11
@ Maxim não pode realmente dizer que meus resultados estão "errados" - foi o que aconteceu na minha máquina. YMMV. Na verdade, eu apenas os executei novamente ( gist.github.com/zaus/014ac9b5a78b267aa1643d63d30c7554 ) em um novo computador de estado sólido Win10 4.0GHz 16GB e obtive resultados semelhantes. O que eu vejo é que o desempenho do hashset era mais consistente, independentemente da localização da chave de pesquisa ou do tamanho da lista, enquanto o desempenho da lista variava muito, de melhor para mais de 300x mais lento. Mas, como PaulWalls comentou inicialmente, estamos falando de #microoptimização séria.
drzaus
@ Maxim para referência: dotnetfiddle.net/5taRDd - fique à vontade para brincar com ele.
drzaus
10

O ponto de equilíbrio dependerá do custo de computação do hash. Os cálculos de hash podem ser triviais ou não ... :-) Sempre existe a classe System.Collections.Specialized.HybridDictionary para ajudá-lo a não precisar se preocupar com o ponto de equilíbrio.

Walden Leverich
fonte
11
Você também precisa levar em consideração o custo de fazer uma comparação. No caso de Contém (T), o HashSet faz uma comparação para verificar se não há uma colisão de Hash versus a Lista fazendo uma comparação em cada item que ele olha antes de encontrar o correto. Você também deve levar em consideração a distribuição dos Hashes gerados por T.GetHashCode () como se isso sempre retornasse o mesmo valor que você está basicamente fazendo com que o HashSet faça o mesmo que List.
Martin Brown
6

A resposta, como sempre, é " depende ". Presumo que as tags que você está falando sobre C #.

Sua melhor aposta é determinar

  1. Um conjunto de dados
  2. Requisitos de uso

e escreva alguns casos de teste.

Também depende de como você classifica a lista (se é que ela é classificada), que tipo de comparações precisam ser feitas, quanto tempo a operação "Comparar" leva para o objeto específico na lista, ou mesmo como você pretende usar o coleção.

Geralmente, o melhor a escolher não se baseia tanto no tamanho dos dados com os quais você está trabalhando, mas na maneira como pretende acessá-los. Você tem cada dado associado a uma sequência específica ou a outros dados? Uma coleção baseada em hash provavelmente seria a melhor. A ordem dos dados que você está armazenando é importante ou você precisará acessar todos os dados ao mesmo tempo? Uma lista regular pode ser melhor então.

Adicional:

Obviamente, meus comentários acima assumem 'desempenho' significa acesso a dados. Outra coisa a considerar: o que você procura quando diz "desempenho"? O valor individual do desempenho é procurado? É gerenciamento de grandes conjuntos de valores (10000, 100000 ou mais)? É o desempenho de preencher a estrutura de dados com dados? Removendo dados? Acessando bits individuais de dados? Substituindo valores? Iterando sobre os valores? Uso de memória? Velocidade de cópia de dados? Por exemplo, se você acessar dados por um valor de cadeia, mas seu principal requisito de desempenho for o uso mínimo de memória, poderá haver problemas de design conflitantes.

Robert P
fonte
5

Você pode usar um HybridDictionary que detecta automaticamente o ponto de interrupção e aceita valores nulos, tornando-o essencialmente o mesmo que um HashSet.

Muis
fonte
11
Promovido isso para a idéia, mas ninguém por favor nunca o usa hoje. Diga não aos não genéricos. Além disso, um dicionário é um mapeamento de valor-chave, o conjunto não é.
Nawfal 29/05
4

Depende. Se a resposta exata realmente importa, faça alguns perfis e descubra. Se você tiver certeza de que nunca terá mais que um certo número de elementos no conjunto, escolha uma Lista. Se o número for ilimitado, use um HashSet.

Adam Rosenfield
fonte
3

Depende do que você está usando. Se suas chaves forem números inteiros, você provavelmente não precisará de muitos itens antes que o HashSet seja mais rápido. Se você o estiver digitando em uma sequência, será mais lento e depende da sequência de entrada.

Certamente você poderia criar uma referência facilmente?

Pedro
fonte
3

Um fator que você não leva em consideração é a robustez da função GetHashcode (). Com uma função de hash perfeita, o HashSet terá claramente um melhor desempenho de pesquisa. Mas, à medida que a função hash diminui, o tempo de pesquisa do HashSet também diminui.

JaredPar
fonte
0

Depende de muitos fatores ... Implementação da lista, arquitetura da CPU, JVM, semântica do loop, complexidade do método equals, etc. as pesquisas superam as pesquisas lineares sem controle e a diferença só aumenta a partir daí.

Espero que isto ajude!

Kyle
fonte
11
JVM ... ou CLR :-)
bvgheluwe