1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6

# конспект · шаг 6 из 6

Конспект: 2-3 деревья и B-деревья

выжимка - её можно унести в заметки

Понятия

2-3 дерево - баланс многоключевыми узлами, без вращений. Узел: 2-УЗЕЛ (1 ключ, 2 ребёнка) или 3-УЗЕЛ (2 ключа, 3 ребёнка); дети - диапазоны между ключами. Все листья ВСЕГДА на одном уровне.

Рост вверх - вставка идёт в ЛИСТ; переполненный узел РАСЩЕПЛЯЕТСЯ, СРЕДНИЙ ключ уходит к родителю; расщепление КОРНЯ надстраивает уровень над всем деревом сразу (все листья опускаются одновременно). Высота ≤ log₂(n+1) без поворотов.

B-дерево - 2-3 дерево, выросшее вширь: узел размером с ДИСКОВЫЙ БЛОК на СОТНИ ключей, ветвление в сотни раз.

Цена на диске - число ЧТЕНИЙ БЛОКОВ (одно чтение в миллионы раз дороже сравнения в памяти), то есть ВЫСОТА. Внутри узла ключи ищут в памяти - почти бесплатно.

Высота B-дерева - ≈ log_b(n): ветвление b в основании логарифма. При b ≈ 200 миллиард ключей = 3-4 уровня = 3-4 чтения диска (у двоичного дерева ~30).

Заём - недобравший узел берёт ключ у соседа через родителя: разделитель вниз, ключ соседа вверх, крайний ребёнок соседа переходит. Слияние - узел + разделитель + сосед в один узел на 2t−2 ключа; родитель теряет ключ.

Что унести

Главная мысль: стоимость операции зависит от уровня памяти (кеш / ОЗУ / диск), и структуру подбирают под неё. Для памяти оптимум - двоичное сбалансированное дерево (АВЛ, красно-чёрное); для диска - широкий узел (B-дерево), потому что там цена - чтения блоков.

двоичное (в памяти) B-дерево (на диске)
ветвление 2 сотни (узел = блок)
высота на 10⁹ ~30 3-4
цена операции сравнения ЧТЕНИЯ БЛОКОВ
где std::map, TreeMap индексы БД, файловые системы

2-3 дерево - концептуальный мост: красно-чёрное дерево = 2-3(-4) дерево, закодированное цветом (3-узел = чёрный + красный ребёнок); B-дерево = 2-3 дерево с узлами на сотни ключей. Идея «узел растёт вширь, дерево - вверх целиком, листья ровно» даёт баланс без вращений и минимальную высоту в блоках.

Формула на память: высота = log_b(n), ветвление в основании. Хочешь дерево ниже (меньше чтений диска) - увеличивай ветвление, а не глубину.

Удаление - зеркало вставки. Ключ убирают из листа (внутренний - через предшественника); недобор чинят заёмом, а если занять не у кого - слиянием, которое может дойти до корня. Опустевший корень убирают: дерево ниже целиком, листья по-прежнему на одной глубине.

Ловушки джокера

Вставлять не в лист 2-3 дерева - структура сломается. Вставка всегда в лист, баланс - расщеплением снизу вверх.

Поднимать при расщеплении не средний ключ - диапазоны детей перестанут соответствовать ключам.

Останавливать расщепление на первом узле - оно может пойти цепочкой до корня.

Считать цену на диске в сравнениях - тогда B-дерево кажется «медленным» (сотни сравнений в узле), хотя чтений диска у него в разы меньше. Цена - чтения блоков.

Двоичное дерево для дискового индекса - высота ~30 = ~30 чтений диска. Нужен широкий узел.

Считать высоту B-дерева как log₂ - забыл про ветвление; правильно log_b, оно кратно меньше.

Удалил ключ из внутреннего узла и склеил детей как попало. Детей должно быть на одного больше, чем ключей; удаление идёт через предшественника из листа.

Проверь себя

Как 2-3 дерево балансируется без вращений и почему листья всегда ровны?

Что поднимают наверх при расщеплении и что происходит при расщеплении корня?

Почему узел B-дерева делают размером с блок?

Что считают ценой поиска на диске и почему высота B-дерева всего 3-4 на миллиардах ключей?

Почему для дискового индекса берут B-дерево, а не красно-чёрное?

Когда недобравший узел B-дерева занимает у соседа, а когда сливается с ним, и как при этом уменьшается высота?

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.