Ефективність словників C #


14

Словники C # - це простий спосіб дізнатися, чи щось існує і т. Д. І т.д. У мене виникає питання, як вони працюють. Скажімо, замість словника я використовую ArrayList. Замість використання ContainsKey(або еквівалентного методу іншою мовою) я проходжу через ArrayList, щоб перевірити, чи існує щось там (або виконую двійковий пошук, якщо дані відсортовані чи щось подібне). Яка різниця в ефективності? Чи є ContainsKeyметод, який використовує якийсь більш ефективний спосіб, а не перебирає ключі і перевіряє, чи є те, що я шукаю?

Якщо скажімо, я створив конкретну хеш-функцію, яка відповідає типу даних, які я маю, і спеціально розроблена для цього набору даних, то так, ця хеш-функція дійсно швидша, ніж прокручування даних. Але словники загальні. Метод ContainsKey не є специфічним для отриманих даних, це загальний метод пошуку.

В основному, про це я прошу. Словники корисні програмістам. Вони включають методи, які допомагають у багатьох речах, і вони поєднують рядки з цілими числами (ключі та значення) та багато іншого. Що стосується ефективності, що вони пропонують? Яка різниця в тому, dictionaryпроти ArrayListзstructs(string,int)


Ви справді порівнюєте яблука з апельсинами. Я думаю, що ключове слово, яке ви шукаєте, це Data Structures посилання на вікі, можливо, вам буде
корисніше

Відповіді:


23

Вам доведеться трохи копати, щоб побачити, як Словник реалізований у C # - Це не так очевидно, як HashMap (хеш-таблиця) або TreeMap (відсортоване дерево) (або ConcurrentSkipListMap - пропускний список ).

Якщо ви перекопаєтесь до розділу "Зауваження":

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

І там ми його маємо. Це хеш-таблиця . Зауважте, що я пов’язав там статтю Вікіпедії - її досить добре читати. Ви можете прочитати розділ щодо роздільної здатності. Можна отримати патологічний набір даних, коли пошук переходить до O (N) (наприклад, все, що ви вставляєте, чомусь потрапляє до того самого хеш-значення або індексу в хеш-таблиці, і вам залишається лінійне зондування ).

Хоча Словник є загальним рішенням, ви не повинні обходити конкретні типи (наприклад, словник) - ви повинні проходити навколо інтерфейсів. У цьому випадку цей інтерфейс є IDictionary( docs ). Для цього ви цілком здатні написати власну реалізацію словника, яка робить все оптимально для ваших даних.

Щодо ефективності різних пошуку / містить?

  • Прогулянка по несортованому списку: O (N)
  • Двійковий пошук відсортованого масиву: O (журнал N)
  • Сортоване дерево: O (журнал N)
  • Таблиця хешу: O (1)

Для більшості людей хеш-таблиця - це те, чого вони хочуть.

Ви можете виявити, що SortedDictionary - це те, що ви хочете замість цього:

SortedDictionary<TKey, TValue>Загальний клас являє собою бінарне дерево пошуку з O (журнал п) вилучення, де п число елементів в словнику. У цьому відношенні він подібний до SortedList<TKey, TValue>родового класу. Два класи мають подібні об'єктні моделі, і обидва мають пошук O (log n).

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

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


5
O (1) не обов'язково "швидкий". Перегляд списку все ще може бути швидшим, ніж хешбел для розмірів колекції, з якими працює програма.
whatsisname

5
@whatsisname ні в якому разі не стверджую, що O (1) швидкий. Це, безумовно, має потенціал бути найшвидшим. Ітерація над ключами хештеля відбувається повільніше, ніж у ArrayList (якщо ви не використовуєте щось на зразок LinkedHashMap, яке надає Java). Важливо знати свої дані та те, як вони поводяться, і вибрати відповідний збір для них - і якщо цього не існує, запишіть їх. Припустимо, звичайно, що таке починання насправді коштує часу (профіль перший!).

У вашій цитаті сказано: "Отримання значення за допомогою його ключа дуже швидке, близьке до O (1), оскільки клас Словник реалізований як хеш-таблиця.", Тому ОП може переплутати два поняття. Іншими словами, я хотів би дати зрозуміти, що великий O не розповідає всієї історії про "швидкість".
whatsisname

3
@whatsisname, безпосередньо від Microsoft. Використання ключа для пошуку значення, якщо ви не маєте патологічного хештеля (який вирішує хеш-зіткнення з яким-небудь іншим механізмом), буде швидше, ніж шукати його у дереві чи відсортованому списку (або несортованому списку). Наприклад, Java використовує лінійне зондування (крок 1) для розв'язання зіткнень - що може бути повільніше у випадках, коли таблиця занадто повна або стикається занадто багато хешей. Однак для загального випадку це досить добре.

Як відповідний приклад, я нещодавно оптимізував деякий код у c ++, який спочатку використовував хеш-таблицю для наборів даних приблизно з 20 записів і займав близько 400 мс для завершення. Перехід на бінарне дерево зводив це до 200 мс, оскільки дерево є більш простим для доступу. Але мені вдалося скоротити це ще за допомогою масиву пар значень імен та евристичної функції пошуку, яка здогадалася, з чого почати шукати на основі шаблонів доступу минулого. Отже, все залежить від того, скільки даних є і які типи шаблонів є в доступі (наприклад, місцевості).
Жуль
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.