Коли вибрати дерево RB, дерево B або дерево AVL?


88

Як програмісту, коли я повинен розглянути можливість використання дерева RB, дерева B або дерева AVL? Які ключові моменти необхідно врахувати, перш ніж прийняти рішення про вибір?

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


10
Ну, я, наприклад, ціную це питання - на даний момент представлений вибір фастульного IntAVLTreeSet проти IntRBTreeSet.
Ян

Відповіді:


113

Візьміть це з дрібкою солі:

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

Дерево RB, коли ви робите досить часті вставки, видалення та отримання в дерево.

Дерево AVL, коли ваші вставки та видалення рідкісні щодо ваших пошуків.


34
Щоб додати трохи детальніше: B-дерева можуть мати різну кількість дочірніх елементів, що дозволяє йому зберігати багато записів, але при цьому зберігати дерево короткої висоти. Дерево RB має менш суворі правила відновлення балансування, які роблять вставки / видалення швидшими, ніж дерево AVL. І навпаки, дерево AVL є більш суворо збалансованим, тому пошук виконується швидше, ніж дерево RB.
pschang

Дерева RB також мають кращу продуктивність O (1) щодо ребалансу, що робить їх більш придатними для стійких структур даних із відкотом та відкотом.

20

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

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

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

Ще одна справа - виділення та звільнення пам’яті. У двійковому дереві це можна відокремити від алгоритмів - користувач може створити вузол, потім викликати алгоритм вставки, а видалення може витягти вузли (від'єднати їх від дерева, але не звільняти пам'ять). У B-дереві або B + -дереві це, очевидно, не працює - дані будуть жити у вузлі, що складається з декількох елементів. Написати методи вставки, які "планують" операцію, не змінюючи вузлів, поки вони не знають, скільки нових вузлів потрібно і що їх можна розподілити, є складною задачею.

Червоний чорний проти AVL? Я не впевнений, що це робить якусь велику різницю. У моїй власній бібліотеці є клас інструментів, який базується на політиці, для маніпулювання вузлами, із методами для подвійних зв’язаних списків, простих бінарних дерев, дерев відтворення, червоно-чорних дерев та обривів, включаючи різні перетворення. Деякі з цих методів були реалізовані лише тому, що мені нудно було в той чи інший час. Я не впевнений, що я навіть перевірив методи витягування. Причиною того, що я вибрав червоно-чорні дерева, а не AVL, є те, що я особисто краще розумію алгоритми - що не означає, що вони простіші, це просто випадковий досвід, який я їм більше знайомий.

Останнє - я лише спочатку розробив свої контейнери з дерева B + як експеримент. Це один з тих експериментів, який ніколи не закінчувався насправді, але це не те, що я заохочував би інших повторювати. Якщо все, що вам потрібно, - це впорядкований контейнер, найкраща відповідь - використовувати той, який надає ваша існуюча бібліотека - наприклад, std :: map і т.д. у C ++. Моя бібліотека еволюціонувала роками, знадобився досить довгий час, щоб вона стала стабільною, і я нещодавно порівняно недавно виявив, що вона технічно не переносна (залежить від трохи невизначеної поведінки WRT offsetof).



0

Вибираючи структури даних, ви торкаєтесь таких факторів, як

  • швидкість пошуку v швидкість оновлення
  • наскільки добре структура справляється з найгіршими операціями, наприклад, вставкою записів, що надходять у відсортованому порядку
  • витрачений простір

Я б почав із прочитання статей у Вікіпедії, на які посилався Роберт Гарві.

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


1
Чесно кажучи, запитав О.П. when should I consider using, ні when should I consider implementing. Хоча останній абзац відповідає дійсності, він не надає великої цінності в контексті цього питання. Навіть з бібліотеками, вам потрібно розуміти алгоритми, щоб ефективно вибрати, яка структура найкраще відповідає вашим бізнес-потребам.
Ден Бешард
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.