Переваги двійкових пошукових дерев над хеш-таблицями


101

Які переваги дерев двійкового пошуку над хеш-таблицями?

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


для хеш-таблиць, який час роботи для find () insert () і delete ()? тета (1) тета (1) і тета (1) правда?
Віддано

8
Майже завжди так. Якщо ви зіткнетеся з великою кількістю зіткнень, то ці часи можуть вирости до O (n).
Крістіан Манн

1
Ці часи також залежать від вашої функції хешування. Якщо з якихось дивних причин це не O (1), очевидно, що ваші операції матимуть мінімальну межу, залежно від ефективності роботи вашої хеш-функції.
Крістіан Манн

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

Відповіді:


93

Пам’ятайте, що двійкові пошукові дерева (на основі довідок) ефективні в пам’яті. Вони не залишають більше пам’яті, ніж потрібно.

Наприклад, якщо хеш-функція має діапазон R(h) = 0...100, вам потрібно виділити масив зі 100 (покажчиків на) елементів, навіть якщо ви просто хешуєте 20 елементів. Якби ви використовували двійкове дерево пошуку для зберігання тієї самої інформації, ви виділяли б лише стільки місця, скільки вам потрібно, а також деякі метадані про посилання.


33
Неправда, що весь діапазон виходів хеш-функцій повинен існувати в масиві. Значення хешу можуть бути просто модифіковані довжиною масиву, щоб дозволити менший масив. Звичайно, кінцева кількість доданих елементів може бути невідома, тому хеш-таблиця все ще може виділити більше місця, ніж потрібно. Бінарні дерева пошуку можуть витратити стільки ж пам’яті чи більше. Пов'язаним реалізаціям потрібно місця принаймні для двох додаткових покажчиків на елемент (три, якщо використовується батьківський вказівник), а BST на основі масиву може витратити багато пам'яті на незаповнені частини дерева.
Соларей

4
@ Solaraeus: BST на основі масиву найкраще порівняти з хеш-таблицями, і вони не є більш марними, ніж хеш-таблиці. Ви також можете розширити BST, використовуючи трохи більше копії пам'яті, порівняно з перерахунком всієї таблиці.
Гуванте

125

Однією з переваг, яку ніхто інший не зазначив, є те, що двійкове дерево пошуку дозволяє ефективно шукати діапазон.

Щоб проілюструвати свою ідею, я хочу зробити крайній випадок. Скажімо, ви хочете отримати всі елементи, чиї ключі від 0 до 5000. А насправді є лише один такий елемент та 10000 інших елементів, чиї ключі не входять у діапазон. BST може виконувати пошук діапазону досить ефективно, оскільки не шукає піддіаграму, на яку неможливо відповісти.

Хоча, як можна здійснювати пошук діапазону в хеш-таблиці? Вам або потрібно повторити кожен простір відра, який є O (n), або ви повинні шукати, чи існує кожен з 1,2,3,4 ... до 5000. (а що стосується клавіш від 0 до 5000 - це нескінченний набір? наприклад, ключі можуть бути десятковими знаками)


11
BSTs роблять пошук діапазону ефективно! Для мене це найкраща відповідь з точки зору практичного та алгоритмічного підходу.
ady

4
ось це справді пояснює, чому дерева так пов'язані з базами даних; їх переваги найбільш помітні, коли вам потрібно виконати фільтрацію на основі ключів. з хеш-картами, вам потрібно переключити всі клавіші, щоб вирішити "знайти всі елементи з ключем від 1000 до 3290"
Дмитро

77

Однією «перевагою» двійкового дерева є те, що воно може пройти для перерахування всіх елементів у порядку. Це не є неможливим для таблиці Hash, але це не нормальна операція, одна конструкція в хешовану структуру.


3
проїзд у будь-якому порядку, ймовірно, не мав би сенсу для хештеля.
FrustratedWithFormsDesigner

2
@FrustratedWithFormsDesigner. Дивіться
сортовану

Дякую за посилання, це пересічна ідея! Я не думаю, що я ніколи не бачив і не використовував цю реалізацію (принаймні, не свідомо).
FrustratedWithFormsDesigner

1
Посилання Wayback Machine на статтю - web.archive.org/web/20100323091632/http://www.concentric.net/…
rahulroy9202

51

Окрім усіх інших хороших коментарів:

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

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

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

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


3
BSTs are much easier to implement in (pure) functional languages compared to hash-tables- справді? Я хочу зараз вивчити функціональну мову!
nawfal

1
Таблиця хешу повинна зберігатись функціональною мовою. Це часто ускладнює реалізацію.
Я ПОДАЮ ВІДПОВІДИ КРАПУ

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

27

Основними перевагами бінарного дерева над хеш-таблицею є те, що бінарне дерево дає дві додаткові операції, які ви не можете (легко, швидко) виконати з хеш-таблицею

  • знайти елемент, найближчий до (не обов'язково рівний) деякому довільному значенню ключа (або найближчому вище / внизу)

  • повторіть вміст дерева в упорядкованому порядку

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


BST знаходить найближчу відповідність, лише якщо точної відповідності не існує, правда? Що робити, якщо ви знайдете точну відповідність у самому корені?
developer747

2
@ developer747: Тоді наступними найближчими внизу та зверху є крайній правий лист лівого піддерева та крайній лівий лист правого піддерева.
Кріс Додд

16

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


3
Щоб повернути цю точку додому, вироджений випадок - це коли колекція містить багато копій всього 1 ключа. у BST вставте O (log n), у таблиці Hash, вставте O (n)
SingleNegationElimination

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

Зауважте, що неврівноважене дерево може перерости у список, а також мати пошук O (n).
awiebe

9

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


8

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


6

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

Ітерація через записи хеш-таблиці просто не має великого сенсу, оскільки всі вони розсіяні в пам'яті.


6

З тріщини інтерв'ю кодування, 6-е видання

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


5

BST також надають операції "findPredecessor" та "findSuccessor" (щоб знайти наступні найменші та наступні за величиною елементи) за час O (logn), що також може бути дуже зручним. Таблиця хешу не може забезпечити ефективність цього часу.


Якщо ви шукаєте операції "findPredecessor" та "findSuccessor", то HashTable - це поганий вибір структури даних в першу чергу.
AKDesai

1

Якщо ви хочете отримати доступ до даних впорядкованому порядку, відсортований список повинен вестись паралельно хеш-таблиці. Хороший приклад - словник у .Net. (див. http://msdn.microsoft.com/en-us/library/3fcwy8h6.aspx ).

Це має побічний ефект не тільки уповільнення вставки, але і вимагає більшого обсягу пам'яті, ніж b-дерево.

Крім того, оскільки b-дерево сортується, легко знайти діапазон результатів або виконати об'єднання або злиття.


1

Це також залежить від використання, Hash дозволяє знайти точну відповідність. Якщо ви хочете запитувати діапазон, то BST - це вибір. Припустимо, у вас багато даних e1, e2, e3 ..... en.

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

Якщо ви хочете знайти значення діапазону більше e41 і менше e8, BST може швидко це знайти.

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

Після заповнення хеш-таблиця повинна збільшити розмір відра і скопіювати знову всі елементи. Це додаткова вартість, що не перевищує BST.


1

Таблиці хешу не корисні для індексації. Коли ви шукаєте діапазон, BST краще. Саме тому більшість індексів баз даних використовують дерева B + замість таблиць Hash


індекси баз даних мають хеш і B + дерева. Якщо ви хочете зробити порівняння, як більше або менше, тоді індекс B + дерев корисний, інакше хеш-індекс корисний для пошуку. Також подумайте, коли дані не порівнянні, і якщо ви хочете створити індекс, тоді db створить хеш-індекс, а не B + дерево індекс. @ssD
Sukhmeet Singh

1

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

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

  1. Максимум
  2. Мінімум
  3. Наступник
  4. Попередник

Усі ці операції, як і кожна операція BST, мають складність у часі O (H). Крім того, всі збережені ключі залишаються відсортованими в BST, таким чином, ви можете отримати відсортовану послідовність клавіш, просто перебравши дерево в порядку.

Якщо підсумовувати, якщо все, що вам потрібно, це операції вставити, видалити та видалити, тоді хеш-таблиця є неперевершеною (більшу частину часу) у виконанні. Але якщо ви хочете виконати будь-які або всі перераховані вище операції, ви повинні використовувати BST, бажано BST, що самоврівноважує.


0

Основна перевага хеш-таблиці полягає в тому, що вона робить майже всі ops в ~ = O (1). І це дуже просто для розуміння та реалізації. Це дійсно ефективно вирішує багато "інтерв'ю". Тож якщо ви хочете зламати інтерв'ю з кодуванням, подружтесь із хеш-таблицею ;-)


Я думаю, що ОП попросило переваги BST над хешированием.
Снайпер

0

Хешмап - це набір асоціативних масивів. Отже, ваш масив вхідних значень збирається у відра. У відкритій схемі адресації у вас є вказівник на відро, і кожен раз, коли ви додаєте нове значення у відро, ви дізнаєтесь, де у відрі є вільні пробіли. Існує кілька способів зробити це - ви починаєте на початку відра і збільшуєте вказівник кожен раз і перевіряєте, чи займає його. Це називається лінійним зондуванням. Потім ви можете здійснити двійковий пошук на зразок додавання, де ви подвоюєте різницю між початком відра та місцем, коли ви подвоюєте або зменшуєте подальше зменшення кожного разу, коли шукаєте вільний простір. Це називається квадратичним зондуванням. ГАРАЗД. Тепер проблеми обох цих методів полягають у тому, що якщо відро переливається у наступну адресу відра, то вам потрібно

  1. Подвійний розмір кожного відра - malloc (N відра) / зміна хеш-функції - Час, необхідний: залежить від реалізації malloc
  2. Перенесіть / скопіюйте кожне з попередніх даних відра у нові дані відра. Це операція O (N), де N представляє цілі дані

ГАРАЗД. але якщо ви використовуєте зв'язаний список, не повинно бути такої проблеми, правда? Так, у пов'язаних списках у вас немає цієї проблеми. Зважаючи на те, що кожне відро починається із пов’язаного списку, і якщо у вас є 100 елементів у відрі, потрібно вимагати переходу цих 100 елементів, щоб дійти до кінця пов'язаного списку, отже List.add (Елемент Е) потребує часу, щоб -

  1. Хеш-елемент до ковша - нормально, як і у всіх реалізаціях
  2. Знайдіть час, щоб знайти останній елемент в операції з ковшем O (N).

Перевага реалізації пов'язаного списку полягає в тому, що вам не потрібна операція розподілу пам'яті та передача / копія O (N) усіх відроків, як у випадку реалізації відкритої адреси.

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


0

Двійкові дерева пошуку можуть бути швидшими при використанні клавіш рядка. Особливо, коли струни довгі.

Двійкові дерева пошуку, використовуючи порівняння для менших / більших, які швидкі для рядків (коли вони не рівні). Таким чином, BST може швидко відповісти, коли рядок не знайдено. Коли його буде знайдено, потрібно буде виконати лише одне повне порівняння.

У хеш-таблиці. Вам потрібно обчислити хеш рядка, і це означає, що вам потрібно пройти всі байти хоча б один раз, щоб обчислити хеш. Потім знову, коли знайдеться відповідна запис.

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