Я думаю, що дерева B + - це хороша загальновпорядкована структура даних контейнерів, навіть в основній пам'яті. Навіть коли віртуальна пам’ять не є проблемою, зручність кешування часто є такою, і дерева B + особливо хороші для послідовного доступу - така ж асимптотична продуктивність, як і зв’язаний список, але зручність кешування близька до простого масиву. Все це та O (log n) шукати, вставляти та видаляти.
Дерева B +, однак, мають проблеми - наприклад, елементи, що рухаються по вузлах, коли ви вставляєте / видаляєте, анулюючи покажчики на ці елементи. У мене є бібліотека контейнерів, яка виконує "обслуговування курсору" - курсори приєднуються до листового вузла, на який вони в даний момент посилаються у пов'язаному списку, тому їх можна виправити або скасувати автоматично. Оскільки рідко буває більше одного-двох курсорів, це працює добре - але це все одно додаткова робота.
Інша справа, що дерево B + є по суті саме таким. Думаю, ви можете позбутися або відтворити нелистові вузли залежно від того, потрібні вони вам чи ні, але з двійковими вузлами дерев ви отримуєте набагато більшу гнучкість. Двійкове дерево можна перетворити у зв’язаний список і назад, не копіюючи вузли - ви просто змінюєте вказівники, а потім пам’ятаєте, що зараз ви розглядаєте його як іншу структуру даних. Крім усього іншого, це означає, що ви отримуєте досить легке O (n) злиття дерев - перетворіть обидва дерева у списки, об'єднайте їх, а потім перетворіть назад у дерево.
Ще одна справа - виділення та звільнення пам’яті. У двійковому дереві це можна відокремити від алгоритмів - користувач може створити вузол, потім викликати алгоритм вставки, а видалення може витягти вузли (від'єднати їх від дерева, але не звільняти пам'ять). У B-дереві або B + -дереві це, очевидно, не працює - дані будуть жити у вузлі, що складається з декількох елементів. Написати методи вставки, які "планують" операцію, не змінюючи вузлів, поки вони не знають, скільки нових вузлів потрібно і що їх можна розподілити, є складною задачею.
Червоний чорний проти AVL? Я не впевнений, що це робить якусь велику різницю. У моїй власній бібліотеці є клас інструментів, який базується на політиці, для маніпулювання вузлами, із методами для подвійних зв’язаних списків, простих бінарних дерев, дерев відтворення, червоно-чорних дерев та обривів, включаючи різні перетворення. Деякі з цих методів були реалізовані лише тому, що мені нудно було в той чи інший час. Я не впевнений, що я навіть перевірив методи витягування. Причиною того, що я вибрав червоно-чорні дерева, а не AVL, є те, що я особисто краще розумію алгоритми - що не означає, що вони простіші, це просто випадковий досвід, який я їм більше знайомий.
Останнє - я лише спочатку розробив свої контейнери з дерева B + як експеримент. Це один з тих експериментів, який ніколи не закінчувався насправді, але це не те, що я заохочував би інших повторювати. Якщо все, що вам потрібно, - це впорядкований контейнер, найкраща відповідь - використовувати той, який надає ваша існуюча бібліотека - наприклад, std :: map і т.д. у C ++. Моя бібліотека еволюціонувала роками, знадобився досить довгий час, щоб вона стала стабільною, і я нещодавно порівняно недавно виявив, що вона технічно не переносна (залежить від трохи невизначеної поведінки WRT offsetof).