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


11

Я хочу впровадити хеш-таблицю за допомогою бінарних дерев пошуку, щоб зменшити складність пошуку в процесі роздільного ланцюга від O (n) (за допомогою пов'язаного списку) до O (log n) (за допомогою BST). Чи можна це зробити, і якщо так, то як? Було б простіше зрозуміти, якщо рішення буде поетапним, реалізацією логіки.

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


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

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

1
@AK_: Так, як ви вже говорили. я хочу вирішити зіткнення за допомогою бінарного дерева пошуку. я трохи виправив своє запитання, щоб зробити його більш зрозумілим.
Авірал

1
Зверніть увагу, що призначається штраф O (n log n) за кожну вставку потім. Як правило, коли у вас є хеш-таблиця, яка починає надмірно заповнюватися (і у вас є ланцюги довше, ніж ви можете терпіти), ви відновлюєте хэш. Якщо ви регулярно стикаєтесь з ланцюгами довше 3 або 4, щось не так.

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

Відповіді:


11

Те, що ви просите, можливо, враховуючи ваші обмеження.

Аналіз

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

Двійкове дерево пошуку (BST) має швидке вставлення та пошук у O (log 2 n). Він також накладає обмеження на елементи, які він зберігає: повинен бути певний спосіб замовити елементи. З огляду на два елементи A і B, що зберігаються в дереві, повинно бути можливо визначити, чи A ставиться перед B або якщо вони мають рівноцінний порядок.

Хеш-таблиця не накладає такого обмеження: елементи в хеш-таблиці повинні мати два властивості. По-перше, повинен бути спосіб визначити, чи є вони рівнозначними; по-друге, повинен бути спосіб обчислити детермінований хеш-код. Замовлення не є вимогою.

Якщо у ваших елементах хеш-таблиці є порядок, тоді ви можете використовувати BST як запис хеш-таблиці для розміщення об'єктів з тим самим хеш-кодом (зіткнення). Однак, завдяки BST, який має пошук і вставку O (log 2 n), це означає, що найгірший випадок для всієї структури (хеш-таблиця плюс BST) технічно кращий, ніж використання списку як запису таблиці. Залежно від впровадження BST, йому буде потрібно більше пам’яті, ніж список, але, швидше за все, не набагато більше.

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

Впровадження

Я не збираюся тут ставити код, бо, чесно кажучи, це насправді не потрібно, і ви все одно не дали мови.

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

Зазвичай я б не виступав за таке кодування копіювання та вставлення. Однак це простий спосіб отримати перевірену в боях структуру даних дуже швидко.


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

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

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

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

7

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

Уолтер Брайт найвідоміший як винахідник мови програмування D , але також написав варіант ECMAScript під назвою DMDScript . Раніше претензія на заголовок DMDScript (або, можливо, пращур - я, мабуть, пам’ятаю ім'я DScript) - полягала в тому, що його хештелі мали перевагу в багатьох подібних мовах. Причина - поводження зіткненнями за допомогою двійкових дерев.

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

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