Як вибрати між хеш-таблицею та трі (префіксним деревом)?


134

Тож якщо мені доведеться вибирати між хеш-таблицею або деревом префіксу, то які дискримінаційні чинники можуть призвести до того, щоб вибрати один за іншим. З моєї власної наївної точки зору, схоже, що використання трие має певні додаткові накладні витрати, оскільки воно не зберігається як масив, але з точки зору часу виконання (якщо вважати, що найдовший ключ - це найдовше англійське слово), це може бути по суті O (1) (стосовно верхньої межі). Може, найдовше англійське слово - 50 символів?

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

Чи може хтось надати мені більш досвідчений погляд на це? Дякую!


1
Варто відзначити, що дерево перенаправлення є більш ефективним, ніж звичайне трие, оскільки вам не потрібна нова гілка для кожного рядкового байта. Крім того, дерева перенаправлення забезпечують підтримку "нечітких" пошуків краще, ніж хеш-таблиці, оскільки ви дивитесь на окремі біти під час роботи вниз по шляху. Наприклад, 00110010може бути вхідний байт, але ви хочете включити відповідність, 00111010видалену лише один біт.
Xeoncross

Відповіді:


116

Переваги спроб:

Основи:

  • Передбачуваний час пошуку O (k), де k - розмір ключа
  • Пошук може зайняти менше k часу, якщо його немає
  • Підтримує замовлений обхід
  • Немає необхідності в хеш-функції
  • Видалення просте

Нові операції:

  • Ви можете швидко шукати префікси клавіш, перераховувати всі записи із заданим префіксом тощо.

Переваги пов'язаної структури:

  • Якщо є багато загальних префіксів, потрібний їм простір.
  • Незмінні спроби можуть поділяти структуру. Замість того, щоб оновлювати трійку на місці, ви можете побудувати нову, яка відрізняється лише вздовж однієї гілки, в іншому місці вказуючи на стару трійку. Це може бути корисно для одночасності, декількох одночасних версій таблиці тощо.
  • Незмінне триє є стисливим. Тобто, він може розділити структуру на суфіксів , а також, з допомогою хеш-consing.

Переваги хештелів:

  • Усі знають хештелі, правда? Ваша система вже матиме приємну добре оптимізовану реалізацію, швидше, ніж спроби для більшості цілей.
  • Ваші ключі не повинні мати особливої ​​структури.
  • Більш економічно простір, ніж очевидна пов'язана структура трійки ( див. Коментарі нижче )

26
не може повністю погодитися з "Більш просторовим, ніж очевидно пов'язана структура трійки" - в загальній реалізації хеш-таблиці вона займає набагато більше місця для вміщення ключів, тоді як у спробах кожен вузол представляє слово. У цьому сенсі спроби є більш просторовими.
галактика

1
як щодо доступу до даних однієї структури проти іншої? Я думаю про кеш і місце розташування
Horia Toma

8
@galactica, що суперечить моєму досвіду: наприклад, у цій відповіді всіх структур, які я вимірював для простору, трійка виявилася найгіршою. Це має сенс, оскільки вказівник набагато більший за байт. Так, обмін префіксами допомагає, але він повинен подолати багато накладних витрат, щоб досягти паритету. Більш ефективне використання простору може допомогти багато, але тоді ми вже не говоримо про очевидну пов'язану структуру.
Дарій Бекон

1
@DariusBacon обробка планів нумерації телефонів видається розумним сценарієм для спроб. Приклад сценарію: номер телефону до оператора, що відповідає номери, перенесені з одного оператора на інший. Для звичайних словників це може залежати від мови (Mandarin vs English), вам потрібні n-грами та / або інші статистичні дані. Для книги з рифмами також здається хорошим варіантом дерево суфіксів.
mbx

Різноманітність даних для пошуку має велике значення. Якщо великий відсоток ваших значень даних унікальний, ваша космічна складність збільшиться за хеш через використання додаткових нульових покажчиків.
Статистика навчання на прикладі

45

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


8
якщо хеш-таблиця та трие мають однакову складність у запиті, O (k) для k довжини рядка, чому ми повинні піти на хеш? ви можете, будь ласка, пояснити?
Саззад Хассейн Хан

29

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

Створення величезних хеш-таблиць для ефективного пошуку не є елегантним рішенням у більшості промислових сценаріїв, де навіть малі затримки / масштабованість мають значення (наприклад, торгівля на високій частоті). Вам потрібно дбати про оптимізовану структуру даних для простору, який він займає в пам'яті, щоб зменшити пропуск кешу.

Дуже хороший приклад, коли трие краще відповідає вимогам, - це посереднє програмне забезпечення для обміну повідомленнями. У вас мільйон підписників і видавців повідомлень різних категорій (в термінах JMS - Теми або обміни); у таких випадках, якщо ви хочете відфільтрувати повідомлення на основі тем (які насправді є рядками), ви точно не хочете створювати хеш-таблицю на мільйон підписок на мільйон тем. Кращим підходом є зберігання тем у трійці, тому коли фільтрація проводиться на основі відповідності тем, її складність не залежить від кількості тем / підписок / видавців (залежить лише від довжини рядка). Мені це подобається, тому що ви можете проявити творчість із цією структурою даних, щоб оптимізувати потреби в просторі, а отже, і мати менші недоліки кешу.


10

Використовуйте дерево:

  1. Якщо вам потрібна функція автоматичного завершення
  2. Знайдіть усі слова, що починаються з 'a' або 'ax' тощо.
  3. Суфіксне дерево - особлива форма дерева. У дерев суфіксів є цілий список переваг, які хеш не може покрити.

4

Щось я не бачив, щоб хтось чітко згадував, що, на мою думку, важливо пам’ятати. Як обидва хеш-таблиці, так і спроби різних видів, як правило, мають O(k)операції, де kдовжина рядка в бітах (або еквівалентно в символах).

Це за умови, що у вас хороша хеш-функція. Якщо ви не хочете, щоб "фермерські" та "сільськогосподарські тварини" мали хеш-одиницю з однаковим значенням, тоді хеш-функція повинна буде використовувати всі біти ключа, і тому хешування "сільськогосподарських тварин" повинно зайняти приблизно вдвічі більше, ніж "ферма" (якщо ви не в якомусь сценарії прокатки хешу, але існують дещо схожі сценарії економії операцій із спробами). І з трійкою ванілі зрозуміло, чому для введення «сільськогосподарських тварин» знадобиться приблизно вдвічі більше, ніж просто «ферма». У перспективі це правда і при стиснених спробах.


3

Вставка та пошук на трійці лінійні з довжиною вхідного рядка O (s).

Хеш дасть вам O (1) для пошуку та вставлення, але спочатку ви повинні обчислити хеш на основі вхідної рядки, яка знову ж таки є O (s).

Висновок, асимптотична часова складність в обох випадках лінійна.

Трійка має трохи більше накладних даних з точки зору даних, але ви можете вибрати стиснуте трійник, який поставить вас знову, більш-менш, на зв’язок із хеш-таблицею.

Щоб розірвати краватку, задайте собі це запитання: чи потрібно шукати лише повні слова? Або мені потрібно повернути всі слова, що відповідають префіксу? (Як і в системі передбачуваного введення тексту). Для першого випадку перейдіть на хеш. Це простіший і чистіший код. Простіше тестувати та підтримувати. Для більш розробленого випадку використання, коли значення префіксів або суфіксів мають значення, перейдіть на трійку.

І якщо ви зробите це просто заради задоволення, реалізація трійки дозволить корисно використати неділю вдень.


"Хеш дасть вам O (1) для пошуку та вставки, але спочатку ви повинні обчислити хеш на основі вхідного рядка, який знову-таки є O (s)." Дякуємо, що пояснили це!
abadawi

2

Реалізація HashTable є просторовою в порівнянні з базовою реалізацією Trie . Але за допомогою рядків замовлення необхідне в більшості практичних застосувань. Але HashTable повністю порушує лексографічний порядок. Тепер, якщо ваша програма виконує операції на основі лексографічного порядку (наприклад, частковий пошук, всі рядки з заданим префіксом, усі слова в упорядкованому порядку), вам слід скористатися Tries. Для лише пошуку HashTable слід використовувати (як, певно, він дає мінімальний час пошуку).

PS: Окрім цих, Термінальні пошукові дерева (TST) були б відмінним вибором. Час його пошуку більше, ніж HashTable, але є часом ефективним для всіх інших операцій. Крім того, його простір більш ефективний, ніж спроби.


-2

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


6
Більшість хеш-таблиць не гарантують відомий час виконання - найгірший випадок - це O (n), якщо кожен елемент стикається і стає ланцюжком
Адам Розенфілд,

2
Для будь-якого набору даних можна обчислити ідеальну хеш-функцію, яка гарантуватиме O (1) пошук цих даних. Звичайно, обчислення ідеального хешу не є безкоштовним.
Джордж В. Рейлі

5
Також ланцюжок - не єдиний спосіб вирішення зіткнень; Є всілякі цікаві, розумні способи вирішити це - хешування зозулі ( en.wikipedia.org/wiki/Cuckoo_hashing ) для одного - і найкращий вибір залежить від потреб клієнтського коду.
Генк Гей

не знав про хешування зозулі та її відношення до фільтра цвітіння, зробимо цікаве прочитання, дякую!
Хорія Тома

Не забувайте про Robin-Hood Hashing, який перевершує кеш-пам'ять і дисперсію. sebastiansylvan.com/2013/05/08/… codecapsule.com/2013/11/11/robin-hood-hashing
Jarred Nicholls
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.