HashSet ile Liste performansı karşılaştırması


405

Genel HashSet<T>sınıfın arama performansının genel sınıftan daha yüksek olduğu açıktır List<T>. Karma tabanlı anahtarı List<T>sınıftaki doğrusal yaklaşımla karşılaştırın .

Bununla birlikte, bir hash anahtarının hesaplanması bazı CPU döngüleri alabilir, bu nedenle az miktarda öğe için doğrusal arama, gerçek bir alternatif olabilir HashSet<T>.

Sorum: Başabaş nerede?

Senaryoyu basitleştirmek (ve adil olmak gerekirse), List<T>sınıfın Equals()bir öğeyi tanımlamak için öğenin yöntemini kullandığını varsayalım .


7
Arama süresini gerçekten en aza indirmek istiyorsanız, dizileri ve sıralı dizileri de göz önünde bulundurun. Bu soruyu doğru bir şekilde cevaplamak için bir kıyaslama gereklidir, ancak bize T hakkında daha fazla bilgi vermeniz gerekir. Ayrıca, HashSet performansı T.GetHashCode () 'un çalışma süresinden etkilenebilir.
Eldritch Conundrum

Yanıtlar:


819

Birçok insan, hızın HashSet<T>her zaman yenilecek bir endişe haline geldiğinde List<T>, bunun ne yaptığınıza bağlı olduğunu söylüyor.

Diyelim List<T>ki içinde sadece ortalama 5 ürün olacak bir tane var. Çok sayıda döngü boyunca, her bir döngüye tek bir öğe eklenir veya kaldırılırsa, a kullanarak daha iyi olabilirsiniz List<T>.

Makinemde bunun için bir test yaptım ve bir avantaj elde etmek için çok küçük olması gerekiyor List<T>. Kısa dizelerin bir listesi için, avantaj, 20 bedeninden sonraki nesneler için 5 bedeninden sonra ortadan kalktı.

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

Grafik olarak görüntülenen veriler:

resim açıklamasını buraya girin

İşte kod:

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();
}

8
Çok teşekkür ederim! Bu harika bir açıklama, List<T>bir oyun motoru için olandan daha hızlı ekleyebilen ve kaldırabilecek bir şey arıyordum ve genellikle yüksek miktarda nesneye sahip olacağım için, bu tür bir koleksiyon mükemmel olurdu.
redcodefinal

17
Aslında, .NET öğesinde, içerdiği öğe sayısına bağlı olarak bir liste ile anlaşılabilir uygulama arasında geçiş yapan bir koleksiyon vardır: HybridDictionary .
MgSam

8
MS sadece jenerik olmayan bir versiyona sahip olduğu için düşüncesinden vazgeçmiş görünüyor.
MgSam

47
Bu cevap tam olarak, liste ile karma arama performansı arasındaki orijinal soruyu cevaplayamaz. Bunlardan ne kadar hızlı ekleyip çıkarabileceğinizi test ediyorsunuz, bu da aramadan çok daha fazla zaman ve farklı performans özellikleri gerektiriyor. .Contains öğesini kullanarak tekrar deneyin; grafiğiniz önemli ölçüde değişecektir.
Robert McKee

5
@hypehuman CPU doğrudan sistem belleğindeki veriler üzerinde çalışamaz, ancak üzerinde çalışmak için verileri bellekten önbelleğine alır. Bellek taşınması isteği ile gerçekte gelen bellek arasında önemli bir gecikme vardır, bu nedenle CPU genellikle aynı anda daha büyük bir bitişik bellek yığını talep eder. Bunun arkasındaki fikir, bir sonraki talimatın ihtiyaç duyduğu hafızanın muhtemelen bir önceki talimatın kullandığı hafızaya çok yakın olması ve bu nedenle çoğu zaman zaten önbellekte olmasıdır. Verileriniz belleğin her tarafına dağıldığında, şanslı olma şansınız azalır.
Roy T.

70

Buna yanlış bakıyorsunuz. Evet, bir Listenin doğrusal araması, az sayıda öğe için bir HashSet'i yener. Ancak performans farkı genellikle küçük koleksiyonlar için önemli değildir. Genellikle endişelenmeniz gereken büyük koleksiyonlar ve Big-O açısından düşündüğünüz yer burası . Bununla birlikte, HashSet performansı üzerinde gerçek bir darboğaz ölçtüyseniz, hibrit bir Liste / HashSet oluşturmayı deneyebilirsiniz, ancak bunu SO'ya sorular sormadan çok sayıda ampirik performans testi yaparak yapabilirsiniz.


5
endişelenmeniz gereken büyük koleksiyonlar . Bu soruyu when small collection becomes large enough to worry about HashSet vs List?onlarca, on binlerce, milyarlarca element olarak yeniden tanımlayabilir miyiz?
om-nom-nom

8
Hayır, birkaç yüz öğenin üzerinde önemli bir performans farkı göreceksiniz. HashSet'in iyi olduğu erişim türlerini yapıyorsanız, her zaman bir HashSet kullanın (örneğin, kümedeki X öğesi.) Koleksiyonunuz o kadar küçükse, Liste daha hızlı olacaksa, bu aramalar çok nadirdir. aslında uygulamanızda bir darboğaz. Bunu bir olarak ölçebilirseniz, optimize etmeyi deneyebilirsiniz - aksi takdirde zamanınızı boşa harcıyorsunuz.
Eloff

15
Bir döngüde birçok kez vurulan küçük bir koleksiyonunuz varsa ne olur? Bu nadir bir senaryo değil.
dan-gph

3
@ om-nom-nom - Bence nokta, devrilme noktasının nerede olduğu önemli değil, çünkü: "Performans bir endişe ise, kullanın HashSet<T>. Daha List<T>hızlı olabilen küçük sayıdaki durumlarda , fark önemsizdir ."
Scott Smith

66

Farklı şekilde davranan performans için iki yapıyı karşılaştırmak aslında anlamsızdır . Amacı ileten yapıyı kullanın. Eğer desem bile senin List<T>çiftleri olmazdı ve yineleme düzeni madde bir etmek o karşılaştırılabilir hale gelmez HashSet<T>kullanımından dolayı onun hala kötü bir seçim List<T>onun nispeten daha az hataya dayanıklı çünkü.

Bununla birlikte , performansın diğer bazı yönlerini inceleyeceğim ,

+------------+--------+-------------+-----------+----------+----------+-----------+
| 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** |
+------------+--------+-------------+-----------+----------+----------+-----------+
  • Her iki durumda da ekleme O (1) olmasına rağmen, hash kodunu saklamadan önce ön hesaplama maliyetini içerdiği için HashSet'te nispeten daha yavaş olacaktır.

  • HashSet'in üstün ölçeklenebilirliğinin bir bellek maliyeti vardır. Her girdi, karma koduyla birlikte yeni bir nesne olarak saklanır. Bu makale size bir fikir verebilir.


11
Sorum (altı yıl önce) teorik performansla ilgili değildi .
Michael Damatov

1
HashSet ElementAt () ile rasgele erişime izin verir ve bu O (n) zaman olacağını düşünüyorum. Ayrıca, belki de her koleksiyonun yinelenmesine izin verip vermediğini masanıza koyabilirsiniz (örneğin: listeler yapar, ancak hashsetler izin vermez).
Dan W

1
Tablodaki @WanW, davranışsal özellikleri değil, yalnızca performansı karşılaştırıyorum. ElementAt ipucu için teşekkürler.
nawfal

1
ElementAt sadece bir LINQ uzantısıdır. Yapamayacağınız hiçbir şey yapmaz ve kendinizi eklediğiniz başka bir yöntemde daha iyi optimize eder. Tablonun ElementAt'ı dikkate almadan daha mantıklı olduğunu düşünüyorum, çünkü diğer tüm yöntemler bu sınıflarda açıkça var.
Dinerdo

Bu tablo için teşekkürler, benim kullanım durumunda, her etkinleştirildiğinde / devre dışı bırakıldığında doldurulmuş bir koleksiyona hedef eklemek ve kaldırmak gerekir ve bu doğru seçim (HashSet) yapmama yardımcı oldu.
Casey Hofland

50

Bir HashSet <> veya Liste <> kullanıp kullanmamanız , koleksiyonunuza nasıl erişmeniz gerektiği ile ilgilidir . Ürünlerin sırasını garanti etmeniz gerekiyorsa, bir Liste kullanın. Bunu yapmazsanız, bir HashSet kullanın. Microsoft'un karma algoritmalarının ve nesnelerinin uygulanması konusunda endişelenmesine izin verin.

Bir HashSet, öğeleri ( O (1) veya yakınındaki karmaşıklığı) numaralandırmak zorunda kalmadan öğelere erişir ve bir Liste, HashSet'in aksine, bazı öğelerin numaralandırılması gerekir (O ​​(n) karmaşıklığı).


Liste, potansiyel olarak belirli bir öğe için ofseti dizinine göre hesaplayabilir (çünkü tüm öğeler aynı türdedir ve potansiyel olarak aynı bellek boyutunu işgal eder). Liste gerekli değildir, elemanlarını numaralandırır
Lu55

@ Lu55 - Soru, koleksiyondaki bir öğeyi aramakla ilgili. Tipik bir senaryo, koleksiyonun dinamik olmasıdır - belirli bir öğeyi son aradığınızdan beri öğeler eklenmiş veya silinmiş olabilir - bu nedenle bir dizin anlamlı değildir (değişmiş olacağı için). Eğer bir varsa statik (eğer hesaplamalar yaparken değişmeyeceği) veya ürün hiçbir zaman silinmez ve her zaman sonunda eklenir koleksiyonu, daha sonra bir Listdurum sensin - sen bir dizin hatırlıyorum çünkü tercih edilir açıklıyorlar.
ToolmakerSteve

Bir HashSet'i sıralamanız gerekiyorsa bir SortedSet kullanabilirsiniz. Hala bir Listeden çok daha hızlı.
canlı aşk

25

Önceki yanıtları göstermek için farklı senaryolar için bazı ölçütlerle karşılaşacağımı düşündüm:

  1. Birkaç (12-20) küçük karakter dizisi (uzunluk 5 ile 10 karakter arasında)
  2. Birçok (~ 10K) küçük tel
  3. Birkaç uzun karakter (uzunluk 200 ile 1000 karakter arasında)
  4. Birçok (~ 5K) uzun tel
  5. Birkaç tamsayı
  6. Birçok (~ 10K) tamsayı

Ve her senaryo için, görünen değerleri aramak:

  1. Listenin başında ("start", dizin 0)
  2. Listenin başına yakın ("erken", dizin 1)
  3. Listenin ortasında ("orta", dizin sayısı / 2)
  4. Listenin sonuna yakın ("geç", dizin sayısı-2)
  5. Listenin sonunda ("son", dizin sayısı-1)

Her senaryodan önce rasgele dizelerin rasgele boyutlu listelerini oluşturdum ve her listeyi bir karma kümesine besledim. Her senaryo 10.000 kez, esasen:

(yalancı kodu test et)

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

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

Örnek Çıktı

Windows 7, 12GB Ram, 64 bit, Xeon 2.8GHz'de test edildi

---------- 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]

7
İlginç. Bunu çalıştırdığınız için teşekkürler. Ne yazık ki, bu tartışmaların gereksiz yeniden düzenlemeleri tetiklediğinden şüpheleniyorum. Umarım çoğu insan için paket, mutlak en kötü durum senaryosunda, tek bir arama yapmak için Listsadece 0,17 milisaniye sürer HashSetve arama sıklığı saçma seviyelere ulaşana kadar bir ikame gerektirmeyecektir . O zamana kadar, List kullanımı genellikle problemlerin en azıdır.
Paul Walls

Bu şimdilik gerçek bilgi değil .. Ya da belki de yanlıştır ... 2 ila 8 karakterden küçük değerleri kontrol ettim. Her 10 değer için List / HashSet oluşturuldu ... HashSet% 30 daha yavaş ... Listedeki kapasite kullanılıyorsa, ~% 40 fark bile. HashSet, yalnızca Listede belirtilen kapasite yoksa ve tüm listeyi eklemeden önce her bir değeri kontrol edersek% 10 daha hızlı olur.
Maxim

Eşya sayısı 4'e düşürülürse, en kötü senaryoda bile (% 10 farkla) Liste tekrar kazanır. Bu nedenle, küçük dizeler koleksiyonu için HashSet'i kullanmanızı önermiyorum (diyelim <20). Ve "birkaç küçük" testinizden farklı olan şey budur.
Maxim

1
@Maxim sonuçlarımın "yanlış" olduğunu söyleyemez - makinemde olan budur. YMMV. Aslında, onları yeni bir Win10 4.0GHz 16GB katı hal bilgisayarında tekrar çalıştırdım ( gist.github.com/zaus/014ac9b5a78b267aa1643d63d30c7554 ) ve benzer sonuçlar aldım. Gördüğüm paket, arama anahtarının nerede olduğu veya listenin ne kadar büyük olduğu fark etmeksizin, hashset performansının daha tutarlı olduğu, ancak liste performansının çılgınca 300x'den daha yavaştan çılgınca değiştiği. Ancak PaulWalls'in başlangıçta yorumladığı gibi ciddi #microoptimization'dan bahsediyoruz.
drzaus

@Max için referans: dotnetfiddle.net/5taRDd - onunla oynamaktan çekinmeyin.
drzaus

10

Başabaş, karma hesaplamanın maliyetine bağlı olacaktır. Karma hesaplamalar önemsiz olabilir ya da olmayabilir ... :-) Her zaman System.Collections.Specialized.HybridDictionary sınıfı vardır, başabaş noktası hakkında endişelenmenize gerek yok.


1
Ayrıca bir karşılaştırma yapmanın maliyetini de dikkate almanız gerekir. İçerir (T) durumunda HashSet, bir Hash çarpışması olmadığından emin olmak için bir karşılaştırma yapacaktır. Liste, doğru olanı bulmadan önce baktığı her öğe üzerinde bir Karşılaştırma yapar. Ayrıca T.GetHashCode () tarafından oluşturulan Hashes dağılımını da hesaba katmanız gerekir, bu her zaman aynı değeri döndürüyorsa, HashSet'i List ile aynı şeyi yaparsınız.
Martin Brown

6

Cevap, her zaman olduğu gibi, " O bağlıdır ". Sanırım C # hakkında konuştuğunuz etiketlerden.

En iyi seçeneğiniz,

  1. Bir veri kümesi
  2. Kullanım gereksinimleri

ve bazı test senaryoları yazın.

Ayrıca listeyi nasıl sıraladığınıza (sıralanıyorsa), ne tür karşılaştırmalar yapılması gerektiğine, listedeki belirli bir nesne için "Karşılaştırma" işleminin ne kadar sürdüğüne, hatta listeyi nasıl kullanmayı planladığınıza da bağlıdır. Toplamak.

Genel olarak, seçilecek en iyisi, üzerinde çalıştığınız verilerin boyutuna değil, ona nasıl erişmeyi planladığınıza bağlı değildir. Belirli bir dizeyle veya başka verilerle ilişkilendirilmiş her bir veri parçanız var mı? Karma tabanlı bir koleksiyon muhtemelen en iyisi olacaktır. Depoladığınız verilerin sırası önemli mi yoksa tüm verilere aynı anda erişmeniz mi gerekiyor? Normal bir liste daha iyi olabilir.

Ek:

Tabii ki, yukarıdaki yorumlarım 'performans' veri erişimi anlamına geliyor. Dikkate alınması gereken başka bir şey: "performans" derken neyi arıyorsun? Performans bireysel değeri aranıyor mu? Büyük (10000, 100000 veya daha fazla) değer kümelerinin yönetimi mi? Veri yapısını veri ile doldurma performansı mı? Veriler kaldırılsın mı? Ayrı veri parçalarına mı erişiyorsunuz? Değerler değiştiriliyor mu? Değerler üzerinde yineleme? Hafıza kullanımı? Veri kopyalama hızı? Örneğin, verilere bir dize değeriyle erişiyorsanız, ancak ana performans gereksiniminiz minimum bellek kullanımı ise, çakışan tasarım sorunlarınız olabilir.


5

Kırılma noktasını otomatik olarak algılayan ve boş değerleri kabul eden bir HybridDictionary kullanabilirsiniz, bu da onu bir HashSet ile aynı yapar.


1
Bunu fikir için oyladı, ancak kimse bugün bunu asla kullanmaz. Jenerik olmayanlara hayır deyin. Ayrıca bir sözlük anahtar / değer eşlemesidir, ayarlanmamıştır.
nawfal

4

Değişir. Kesin cevap gerçekten önemliyse, biraz profilleme yapın ve öğrenin. Sette asla belirli sayıda öğeden daha fazlasına sahip olamayacağınızdan eminseniz, bir Liste ile devam edin. Sayı sınırsızsa, bir HashSet kullanın.


3

Ne hash yaptığınıza bağlıdır. Anahtarlarınız tamsayı ise, HashSet daha hızlı olmadan çok fazla öğeye ihtiyacınız yoktur. Bir dizgeye tuşluyorsanız, daha yavaş olacaktır ve giriş dizesine bağlıdır.

Şüphesiz bir ölçütleri kolayca kırbaçlayabilir misiniz?


3

Dikkate almamanız gereken faktörlerden biri GetHashcode () işlevinin sağlamlığıdır. Mükemmel bir karma işleviyle HashSet açıkça daha iyi arama performansına sahip olacaktır. Ancak hash işlevi azaldıkça HashSet arama süresi de düşer.


0

Bir çok faktöre bağlıdır ... Liste uygulaması, CPU mimarisi, JVM, döngü semantiği, eşitlik yönteminin karmaşıklığı vb. aramalar doğrusal aramaları elden çıkarır ve fark sadece oradan ölçeklenir.

Bu yardımcı olur umarım!


1
JVM ... veya CLR :-)
bvgheluwe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.