Открыть сервис

Сбалансированное бинарное дерево

Сбалансированное бинарное дерево (самобалансирующееся дерево) — это структура данных, представляющая собой бинарное дерево поиска, в котором автоматически поддерживается приблизительно равная высота левого и правого поддеревьев для каждого узла. Основная цель балансировки — гарантировать, что время выполнения основных операций (поиск, вставка, удаление) остаётся логарифмическим (O(log n)), предотвращая вырождение дерева в линейный список.

История и мотивация

Бинарные деревья поиска (БДП) — одна из фундаментальных структур данных, позволяющая эффективно хранить и извлекать упорядоченные данные. Однако в классическом БДП форма дерева сильно зависит от порядка вставки элементов. Если данные поступают в отсортированном или почти отсортированном порядке, дерево вырождается в несбалансированную структуру, напоминающую связный список. В таком случае высота дерева становится равной количеству элементов (n), а время выполнения операций — линейным (O(n)), что сводит на нет преимущества бинарного поиска.

Проблема вырождения была известна с момента появления БДП. Первые попытки её решения привели к созданию сбалансированных деревьев. В 1962 году советские учёные Георгий Адельсон-Вельский и Евгений Ландис предложили АВЛ-дерево — первую известную самобалансирующуюся структуру. Позднее, в 1972 году, Рудольф Байер и Эдвард МакКрейт разработали красно-чёрное дерево, которое стало основой для многих реализаций в стандартных библиотеках языков программирования (например, std::map в C++ и TreeMap в Java). В 1970-х годах также появились B-деревья, сбалансированные деревья для работы с внешней памятью.

Принцип балансировки

Балансировка достигается за счёт наложения дополнительных условий на структуру дерева и выполнения специальных операций — поворотов (rotations). Поворот — это локальная операция, которая изменяет структуру дерева, сохраняя при этом свойство бинарного дерева поиска. Существует два основных типа поворотов: правый (clockwise) и левый (counterclockwise). В более сложных случаях применяются комбинации поворотов (например, лево-правый или право-левый).

Каждый узел хранит дополнительную информацию, которая используется для оценки степени сбалансированности. В зависимости от типа дерева это может быть:

  • Высота поддерева (в АВЛ-деревьях).
  • Цвет узла (в красно-чёрных деревьях).
  • Размер поддерева (в деревьях с весовым балансом).

После каждой операции вставки или удаления алгоритм проверяет, не нарушены ли условия балансировки, и при необходимости выполняет последовательность поворотов для восстановления свойств.

Основные виды сбалансированных бинарных деревьев

АВЛ-дерево

АВЛ-дерево (по фамилиям создателей: Адельсон-Вельский и Ландис) — строго сбалансированное дерево. Для каждого узла разница высот левого и правого поддеревьев (коэффициент сбалансированности) не превышает 1 по модулю. Если после вставки или удаления это условие нарушается, выполняется один из четырёх типов поворотов (LL, RR, LR, RL). АВЛ-деревья обеспечивают наилучшую гарантированную высоту (не более 1.44 * log₂(n)), но требуют более частых поворотов при вставке и удалении.

Красно-чёрное дерево

Красно-чёрное дерево — менее строго сбалансированная, но более эффективная на практике структура. Каждый узел окрашен в красный или чёрный цвет. Соблюдаются следующие правила:

  1. Корень всегда чёрный.
  2. Листья (nil-узлы) считаются чёрными.
  3. У красного узла оба потомка — чёрные (нет двух красных узлов подряд).
  4. Для любого узла все пути от него до листьев содержат одинаковое количество чёрных узлов.

Эти правила гарантируют, что самый длинный путь от корня до листа не более чем в два раза превышает самый короткий. Высота красно-чёрного дерева не превышает 2 * log₂(n+1). Красно-чёрные деревья требуют меньше поворотов при вставке (не более 2) и удалении (не более 3), чем АВЛ-деревья.

Декартово дерево (Treap)

Декартово дерево (или treap — от tree + heap) сочетает свойства бинарного дерева поиска и кучи. Каждый узел содержит ключ (для упорядочивания как в БДП) и случайный приоритет (для поддержания структуры кучи). Балансировка достигается за счёт случайности: приоритеты распределяются случайным образом, что с высокой вероятностью обеспечивает логарифмическую высоту. Treap не гарантирует строгой сбалансированности, но на практике работает эффективно и проще в реализации, чем АВЛ или красно-чёрное дерево.

Splay-дерево

Splay-дерево — самобалансирующееся дерево, которое не хранит дополнительной информации о балансе. Вместо этого после каждой операции (поиск, вставка, удаление) выполняется процедура splay — поднятие узла к корню с помощью последовательности поворотов. Это приводит к тому, что часто используемые элементы оказываются ближе к корню, что улучшает производительность для реальных сценариев доступа. Амортизированная сложность операций — O(log n).

B-дерево

B-дерево — обобщение бинарного дерева, в котором каждый узел может содержать более двух потомков (и, соответственно, несколько ключей). B-деревья специально спроектированы для работы с блочно-ориентированной памятью (диски, SSD). Они минимизируют количество обращений к внешней памяти, так как один узел обычно соответствует одному блоку данных. Хотя B-деревья не являются бинарными в строгом смысле, они часто рассматриваются в контексте сбалансированных деревьев.

Применение

Сбалансированные бинарные деревья широко используются в различных областях информатики:

  • Базы данных: B-деревья и их варианты (B+, B*) являются основой для построения индексов в большинстве реляционных СУБД (PostgreSQL, MySQL, Oracle).
  • Стандартные библиотеки: красно-чёрные деревья реализованы в std::map и std::set (C++), TreeMap и TreeSet (Java), а также в dict (Python, с версии 3.7 — упорядоченные словари).
  • Файловые системы: некоторые файловые системы (например, NTFS) используют B-деревья для каталогов.
  • Компиляторы: для хранения таблиц символов и синтаксических деревьев.
  • Сетевые маршрутизаторы: для хранения таблиц маршрутизации (обычно используются Patricia trie, но сбалансированные деревья также применяются).
  • Графические движки: для пространственного разделения объектов (например, деревья отрезков).

Сравнение характеристик

Тип дереваСтрогость балансаВысота (в худшем случае)Повороты при вставкеДополнительная память на узел
АВЛСтрогий1.44 log₂(n)O(log n) (до 2)1 бит или 1 целое (высота)
Красно-чёрноеУмеренный2 log₂(n+1)O(1) (до 2)1 бит (цвет)
TreapВероятностныйO(log n) с высокой вероятностьюO(1)1 целое (приоритет)
SplayАмортизированныйO(n) (но амортизированно O(log n))O(1) (splay)0 (нет доп. данных)
B-деревоСтрогийO(log_m n) (m — порядок)O(log_m n)Массив ключей и указателей

Реализация в России

В России сбалансированные деревья изучаются в рамках курсов по алгоритмам и структурам данных во всех ведущих технических вузах (МГУ, МФТИ, СПбГУ, ВШЭ). АВЛ-дерево, как изобретение советских учёных, традиционно занимает важное место в учебных программах. Существуют российские реализации библиотек, включающих сбалансированные деревья, например, в составе свободного программного обеспечения (библиотека glib от GNOME, используемая в том числе в российских дистрибутивах Linux).

Критика и ограничения

Несмотря на широкое распространение, сбалансированные деревья имеют определённые недостатки:

  • Накладные расходы на балансировку: каждая операция вставки и удаления требует дополнительных вычислений и поворотов, что может снижать производительность в сценариях с интенсивными изменениями данных.
  • Дополнительная память: хранение информации о балансе (цвет, высота, приоритет) увеличивает размер каждого узла.
  • Сложность реализации: особенно для АВЛ-деревьев и красно-чёрных деревьев, где требуется аккуратная обработка множества случаев.
  • Альтернативы: для некоторых задач более эффективными могут быть хеш-таблицы (для неупорядоченных данных) или скип-листы (для упорядоченных данных с простой реализацией).

Тем не менее, сбалансированные бинарные деревья остаются одним из ключевых инструментов в арсенале разработчика, обеспечивая гарантированную производительность для упорядоченных данных.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →