Продуктивність HashSet vs. List


404

Зрозуміло, що ефективність пошуку родового HashSet<T>класу вище, ніж у загального List<T>класу. Просто порівняйте ключ на основі хешу з лінійним підходом у List<T>класі.

Однак обчислення хеш-ключа може самостійно займати деякі цикли процесора, тому для невеликої кількості елементів лінійний пошук може бути реальною альтернативою HashSet<T>.

Моє запитання: де беззбитковість?

Для спрощення сценарію (і справедливості) припустимо, що List<T>клас використовує Equals()метод елемента для ідентифікації елемента.


7
Якщо ви дійсно хочете мінімізувати час пошуку, також врахуйте масиви та відсортовані масиви. Щоб правильно відповісти на це запитання, потрібен орієнтир, але вам потрібно розповісти більше про Т. Також на продуктивність HashSet може вплинути час роботи T.GetHashCode ().
Eundritch Conundrum

Відповіді:


818

Дуже багато людей говорять, що як тільки ти досягнеш того розміру, коли швидкість насправді є проблемою, яка HashSet<T>завжди буде бити List<T>, але це залежить від того, що ти робиш.

Скажімо, у вас є лише List<T>те, що в ньому буде в середньому 5 предметів. За велику кількість циклів, якщо кожен цикл додається або видаляється один елемент, вам може бути краще використовувати a List<T>.

Я зробив тест на це на своїй машині, і, ну, це має бути дуже маленьким, щоб отримати перевагу List<T>. Для списку коротких рядків перевага пішла після розміру 5, для об’єктів після розміру 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

Ось ці дані, відображені у вигляді графіка:

введіть тут опис зображення

Ось код:

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
Дуже дякую! Це чудове пояснення, я шукав щось, що могло б додавати та видаляти швидше, ніж List<T>для ігрового двигуна, і оскільки у мене зазвичай буде великий об єкт, ця колекція була б ідеальною.
redcodefinal

17
Фактично є колекція в .NET рамках, яка перемикається між списком і hastable реалізацією залежно від кількості елементів, які він містить: HybridDictionary .
MgSam

8
МС, схоже, відмовився від цієї думки, оскільки у неї є лише негенерична версія.
MgSam

47
Наскільки повна ця відповідь, вона не відповідає на початкове запитання щодо результатів пошуку списку та хештету. Ви випробовуєте, наскільки швидко ви можете вставити та видалити з них, що вимагає значно більше часу та інших характеристик продуктивності, ніж пошук. Спробуйте ще раз, використовуючи .Contains, і ваш графік істотно зміниться.
Роберт Маккі

5
@hypehuman ЦП не може працювати безпосередньо над даними в системній пам'яті, але забирає дані з пам'яті в кеш-пам'ять для роботи. Існує значна затримка між запитом про переміщення пам’яті та фактично прибуваючою пам'яттю, тому процесор часто вимагає відразу перенести більший шматок суміжної пам’яті. Ідея цього полягає в тому, що пам'ять, необхідна наступною інструкцією, ймовірно, дуже близька до пам'яті, використовуваної попередньою інструкцією, і тому часто вже знаходиться в кеші. Коли ваші дані будуть розкидані по всій пам'яті, шанс на щастя зменшується.
Рой Т.

70

Ви дивитесь на це неправильно. Так, лінійний пошук списку обіграє HashSet для невеликої кількості елементів. Але різниця в продуктивності зазвичай не має значення для невеликих колекцій. Це, як правило, великі колекції, про які ви повинні турбуватися, і саме там ви думаєте з точки зору Big-O . Однак, якщо ви виміряли реальне вузьке місце щодо продуктивності HashSet, ви можете спробувати створити гібридний List / HashSet, але ви зробите це, проводячи багато емпіричних тестів на ефективність роботи - не задаючи питань щодо SO.


5
великі колекції, про які ви повинні турбуватися . Ми можемо переосмислити це питання через when small collection becomes large enough to worry about HashSet vs List?десятки, десятки тисяч, мільярди елементів?
om-nom-nom

8
Ні, ви побачите значну різницю в продуктивності вище кількох сотень елементів. Суть у тому, щоб завжди використовувати HashSet, якщо ви робите типи доступу, в яких HashSet хороший (наприклад, елемент X у наборі.) Якщо ваша колекція настільки мала, що список швидший, то дуже рідко трапляються ці пошуки насправді вузьке місце у вашій заяві. Якщо ви можете виміряти його як один, добре, ви можете спробувати оптимізувати його, але в іншому випадку ви витрачаєте свій час.
Eloff

15
Що робити, якщо у вас є невелика колекція, яка потрапляє багато разів у цикл? Це не рідкий сценарій.
дан-gph

3
@ om-nom-nom - Я думаю, справа в тому, що не має значення, де переломний момент, тому що: "Якщо продуктивність турбує, використовуйте HashSet<T>. У невеликих випадках, коли це List<T>може бути швидше, різниця незначна. . "
Скотт Сміт

66

По суті безглуздо порівнювати дві структури по продуктивності, які ведуть себе по-різному. Використовуйте структуру, яка передає наміри. Навіть якщо ви кажете, що у вас List<T>не було б дублікатів, а порядок ітерації не має значення, щоб зробити його порівнянним з a HashSet<T>, його все одно поганий вибір для використання, List<T>оскільки його відносно менш стійкий до помилок.

Однак, я перевірю деякі інші аспекти діяльності,

+------------+--------+-------------+-----------+----------+----------+-----------+
| 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** |
+------------+--------+-------------+-----------+----------+----------+-----------+
  • Хоча додавання є O (1) в обох випадках, воно буде відносно повільніше в HashSet, оскільки воно включає вартість попереднього обчислення хеш-коду перед його зберіганням.

  • Чудова масштабованість HashSet має вартість пам'яті. Кожен запис зберігається як новий об’єкт разом з його хеш-кодом. Ця стаття може дати вам ідею.


11
Моє запитання (шість років тому) стосувалося не теоретичних показників.
Михайло Даматов

1
HashSet дозволяє дозволити випадковий доступ з ElementAt (), і я думаю, що це був би O (n) час. Крім того, можливо, ви можете помістити у свою таблицю, чи дозволяє кожна колекція дублікатів (наприклад, списки роблять, але хештети - ні).
Dan W

1
@DanW в таблиці Я порівнюю чисто характеристики, а не поведінкові характеристики. Дякуємо за пораду ElementAt.
nawfal

1
ElementAt - це лише розширення LINQ. Він не робить нічого, чого не вдається зробити, і краще оптимізувати інший метод, який ви додаєте самостійно. Я думаю, що таблиця мала більше сенсу, не враховуючи ElementAt, оскільки всі інші методи існують на цих класах явно.
Дінердо

Дякуємо за цю таблицю, у моєму випадку використання мені потрібно додавати та видаляти цілі до заселеної колекції щоразу, коли вони вмикаються / вимикаються, і це допомогло мені зробити правильний вибір (HashSet).
Кейсі Хофланд

50

Чи використовувати HashSet <> або Список <>, зводиться до того, як вам потрібно отримати доступ до своєї колекції . Якщо вам потрібно гарантувати порядок товарів, скористайтеся Переліком. Якщо цього не зробити, використовуйте HashSet. Нехай Microsoft потурбується про реалізацію алгоритмів і об'єктів хешування.

HashSet матиме доступ до елементів, не перераховуючи колекцію (складність O (1) або поблизу неї), і оскільки Список гарантує порядок, на відміну від HashSet, деякі елементи доведеться перераховувати (складність O (n)).


Список потенційно може обчислити зміщення для конкретного елемента за його індексом (оскільки всі елементи одного типу і потенційно мають однаковий розмір пам'яті). Тож Список не обов’язково перераховує, що це елементи
Lu55

@ Lu55 - Питання про пошук елемента в колекції. Типовий сценарій полягає в тому, що колекція є динамічною - елементи, можливо, були додані або видалені з останнього разу, коли ви шукали певний елемент, - тому індекс не має сенсу (тому що він змінився). Якщо у вас є статична колекція (яка не зміниться під час виконання ваших обчислень) або елементи ніколи не видаляються і завжди додаються в кінці, то Listкращим є a , тому що ви можете запам'ятати індекс - така ситуація ви описують.
ToolmakerSteve

Ви можете використовувати SortedSet, якщо вам потрібно сортувати HashSet. Ще набагато швидше, ніж Список.
live-love

25

Я просто подумав, що я би задзвонив деякі орієнтири для різних сценаріїв, щоб проілюструвати попередні відповіді:

  1. Кілька (12 - 20) невеликих рядків (довжиною від 5 до 10 символів)
  2. Багато (~ 10 К) невеликих струн
  3. Кілька довгих рядків (довжиною від 200 до 1000 символів)
  4. Багато (~ 5 К) довгих струн
  5. Кілька цілих чисел
  6. Багато (~ 10 К) цілих чисел

І для кожного сценарію шукайте значення, які з'являються:

  1. На початку списку ("старт", індекс 0)
  2. Біля початку списку ("рано", індекс 1)
  3. У середині списку ("середина", кількість покажчиків / 2)
  4. У кінці списку ("пізно", кількість індексів-2)
  5. В кінці списку ("кінець", кількість індексів-1)

Перед кожним сценарієм я генерував випадкові розміри списків випадкових рядків, а потім подавав кожен список до хештету. Кожен сценарій працював 10 000 разів, по суті:

(тестовий псевдокод)

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

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

Вибірка зразка

Тестовано на Windows 7, 12 ГБ оперативної пам’яті, 64 біт, Xeon 2,8 ГГц

---------- 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
Цікаво. Дякуємо, що запустили це. На жаль, я підозрюю, що ці дискусії викликають непотрібні рефактори. Сподіваємось, що для більшості людей винос займає те, що у вашому абсолютно гіршому випадку Listвсе-таки знадобиться всього 0,17 мілісекунд, щоб здійснити один пошук, і, швидше за все, не буде потрібно заміна, HashSetпоки частота пошуку не досягне абсурдних рівнів. На той час, як правило, використання Списку є найменшою проблемою.
Пол Стіна

Це наразі не є фактичною інформацією. А може, це спочатку неправильно ... Я просто перевірив невеликі значення від 2 до 8 знаків. Список / HashSet були створені для кожні 10 значень ... HashSet повільніше на 30% ... Якщо використовується місткість у List, різниця навіть ~ 40%. HashSet стає швидшим на 10%, лише якщо ми Список без вказаної ємності і перевіряємо кожне значення перед додаванням через весь список.
Максим

Якщо кількість предметів зменшиться до 4, то Список знову виграє навіть у гіршому сценарії (з 10% різницею). Тому я не рекомендую використовувати HashSet для невеликої колекції рядків (скажімо, <20). І це те, чим відрізняється від ваших «декількох маленьких» тестів.
Максим

1
@Maxim насправді не може сказати, що мої результати "неправильні" - це сталося на моїй машині. YMMV. Насправді я просто запустив їх знову ( gist.github.com/zaus/014ac9b5a78b267aa1643d63d30c7554 ) на новому твердотільному комп'ютері Win10 4,0 ГГц і отримав подібні результати. Я вважаю, що продуктивність хештетів була більш послідовною, незалежно від того, де знаходився ключ пошуку чи наскільки великий список, тоді як продуктивність списку дивовижно змінювалася від кращого до більш ніж на 300 разів повільніше. Але, як спочатку прокоментував Пол Уоллс, ми говоримо про серйозну #мікрооптимізацію.
drzaus

@Maxim для довідки: dotnetfiddle.net/5taRDd - сміливо пограйте з нею.
drzaus

10

Беззбитковість залежатиме від витрат на обчислення хешу. Хеш-обчислення можуть бути тривіальними, чи ні ... :-) Завжди існує клас System.Collections.Specialized.HybridDictionary, який допоможе вам не турбуватися з приводу точки беззбитковості.


1
Також потрібно враховувати витрати на порівняння. У випадку, що містить Contains (T), HashSet зробить порівняння, щоб перевірити, чи не має зіткнення хеш-вершини зі списком, зробивши порівняння по кожному елементу, який він розглядає, перш ніж знайде правильний. Ви також повинні враховувати розподіл хешів, згенерованих T.GetHashCode (), як ніби це завжди повертає те саме значення, яке ви в основному змушуєте HashSet робити те саме, що і List.
Мартін Браун

6

Відповідь, як завжди, - це " Це залежить ". Я припускаю, що з тегів ви говорите про C #.

Ваша найкраща ставка - визначитись

  1. Набір даних
  2. Вимоги до використання

і написати кілька тестових випадків.

Це також залежить від того, як ви сортуєте список (якщо він взагалі відсортований), які порівняння потрібно проводити, скільки часу займає операція "Порівняти" для конкретного об'єкта у списку або навіть як ви плануєте використовувати колекція.

Як правило, найкращий вибір не стільки ґрунтується на розмірі даних, з якими ви працюєте, скільки на тому, як ви маєте намір отримати доступ до нього. Чи є у вас кожен фрагмент даних, пов'язаний з певним рядком чи іншими даними? Колекція на основі хешу, мабуть, найкраща. Чи важливий порядок даних, які ви зберігаєте, або вам буде потрібно мати доступ до всіх даних одночасно? Звичайний список може бути тоді кращим.

Додатково:

Звичайно, мої вище коментарі припускають, що «продуктивність» означає доступ до даних. Ще щось, що слід врахувати: що ви шукаєте, коли говорите "вистава"? Чи підвищується індивідуальна цінність ефективності? Це управління великими (10000, 100000 і більше) наборами значень? Це ефективність заповнення структури даних даними? Видалення даних? Доступ до окремих бітів даних? Заміна значень? Ітерація над значеннями? Використання пам'яті? Швидкість копіювання даних? Наприклад, якщо ви отримуєте доступ до даних за значенням рядка, але ваша основна вимога до продуктивності - мінімальне використання пам'яті, у вас можуть виникнути конфліктні проблеми з дизайном.


5

Ви можете використовувати HybridDictionary, який автоматично визначає точку злому і приймає нульові значення, роблячи це істотно таким же, як і HashSet.


1
Це підтримали цю ідею, але сьогодні ніхто ніколи не використовує це. Не кажіть негенерікам. Також словник - це відображення ключових значень, набір - ні.
nawfal

4

Це залежить. Якщо точна відповідь насправді має значення, зробіть кілька профілів та з’ясуйте. Якщо ви впевнені, що в наборі ніколи не буде більше певної кількості елементів, перейдіть зі списком. Якщо число не обмежене, використовуйте HashSet.


3

Залежить від того, що ти хешиш. Якщо ваші ключі цілими числами, вам, швидше за все, не потрібно дуже багато елементів, перш ніж HashSet стане швидшим. Якщо ви вводите клавішу на рядок, це буде повільніше і залежить від введення рядка.

Невже ви могли досить легко збити еталон?


3

Одним із факторів, який ви не враховуєте, є надійність функції GetHashcode (). Завдяки ідеальній хеш-функції HashSet очевидно матиме кращі результати пошуку. Але як зменшується хеш-функція, так і час пошуку HashSet.


0

Залежить від безлічі факторів ... Реалізація списку, архітектура процесора, JVM, циклічна семантика, складність методу рівних тощо. На той час список стає достатньо великим для ефективного орієнтування (1000+ елементів), бінарних файлів на основі хеша пошукові запити перемагають лінійні пошуки вниз, і різниця лише збільшується звідти.

Сподіваюся, це допомагає!


1
JVM ... або CLR :-)
bvgheluwe
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.