АВЛ-дерево
АВЛ-дерево — это сбалансированное по высоте бинарное дерево поиска, в котором для каждого узла выполняется условие: разность высот его левого и правого поддеревьев (коэффициент сбалансированности) не превышает по модулю единицы. Названо в честь советских учёных Георгия Адельсона-Вельского и Евгения Ландиса, впервые описавших структуру в 1962 году. АВЛ-дерево является одной из первых исторически предложенных самобалансирующихся структур данных и обеспечивает логарифмическую сложность операций поиска, вставки и удаления в худшем случае.
История
АВЛ-дерево было предложено в 1962 году в работе «Алгоритм организации информации» (авторы: Г. М. Адельсон-Вельский, Е. М. Ландис), опубликованной в журнале «Доклады Академии наук СССР». До этого основным способом организации данных в оперативной памяти были неотбалансированные бинарные деревья поиска, которые в худшем случае (например, при вставке отсортированных данных) вырождались в линейный список, сводя сложность операций к O(n). Разработка АВЛ-дерева решила эту проблему, введя строгий критерий баланса и механизм его восстановления.
В 1964 году Ландис и Адельсон-Вельский опубликовали расширенное описание, а впоследствии структура вошла во все классические учебники по алгоритмам и структурам данных. В 1970-х годах появились альтернативные самобалансирующиеся деревья (например, красно-чёрные деревья), которые менее строго контролируют баланс, но требуют меньше операций при вставке и удалении. Тем не менее АВЛ-дерево остаётся востребованным в приложениях, где критична скорость поиска.
Определение и свойства
Бинарное дерево поиска
АВЛ-дерево является частным случаем бинарного дерева поиска, то есть для любого узла дерева выполняется:
- все ключи в левом поддереве меньше ключа данного узла;
- все ключи в правом поддереве больше ключа данного узла.
Коэффициент сбалансированности
Для каждого узла вводится характеристика — коэффициент сбалансированности (balance factor), вычисляемый как разность высот левого и правого поддеревьев: \[ BF = h(левое) - h(правое) \] Высота пустого поддерева принимается равной −1. В АВЛ-дереве для всех узлов выполняется условие: \[ BF \in \{-1, 0, 1\} \] Если после вставки или удаления узла это условие нарушается, дерево считается разбалансированным и требует перестройки.
Высота дерева
Высота АВЛ-дерева с n узлами в худшем случае составляет примерно \( \log_{\varphi}(n+2) - 1 \), где \(\varphi\) — золотое сечение (≈1,618). Это даёт оценку \( O(\log n) \). Минимальная высота для n узлов — \( \lceil \log_2(n+1) \rceil \). Таким образом, все основные операции выполняются за логарифмическое время.
Операции
Поиск
Поиск элемента в АВЛ-дереве выполняется так же, как в обычном бинарном дереве поиска: начиная с корня, сравниваем ключ с текущим узлом и переходим в левое или правое поддерево. Сложность — \( O(\log n) \).
Вставка
Вставка нового узла происходит в два этапа:
- Стандартная вставка в бинарное дерево поиска: узел добавляется как лист в соответствующую позицию.
- Балансировка: после вставки необходимо проверить коэффициенты сбалансированности всех узлов на пути от нового узла к корню. Если у какого-либо узла коэффициент выходит за пределы \([-1, 1]\), выполняется одно из четырёх вращений (см. ниже).
Удаление
Удаление узла также состоит из двух этапов:
- Стандартное удаление из бинарного дерева поиска (с заменой на самый левый узел правого поддерева или самый правый узел левого поддерева, если удаляемый узел имеет двух потомков).
- Балансировка: проверка и восстановление баланса для всех узлов на пути от места удаления к корню. В отличие от вставки, при удалении может потребоваться несколько вращений.
Вращения
Для восстановления баланса используются четыре типа поворотов (вращений) поддеревьев:
- Правый поворот (LL-поворот): выполняется, когда левое поддерево узла на два уровня выше правого (BF = 2), и левый потомок имеет BF = 0 или 1.
- Левый поворот (RR-поворот): выполняется, когда правое поддерево узла на два уровня выше левого (BF = −2), и правый потомок имеет BF = 0 или −1.
- Левый-правый поворот (LR-поворот): сначала левый поворот вокруг левого потомка, затем правый поворот вокруг исходного узла. Применяется при BF = 2 и BF левого потомка = −1.
- Правый-левый поворот (RL-поворот): сначала правый поворот вокруг правого потомка, затем левый поворот вокруг исходного узла. Применяется при BF = −2 и BF правого потомка = 1.
Каждое вращение изменяет структуру дерева локально, сохраняя свойство бинарного дерева поиска и восстанавливая баланс.
Сравнение с другими структурами
Красно-чёрное дерево
Красно-чёрное дерево — менее строго сбалансированная структура: оно гарантирует, что высота не превышает \( 2 \log_2(n+1) \). Вставка и удаление в красно-чёрном дереве требуют в среднем меньше поворотов (не более 2 при вставке, не более 3 при удалении), чем в АВЛ-дереве (до \( O(\log n) \) при удалении). Однако АВЛ-дерево обеспечивает более быстрый поиск, так как его высота ближе к минимально возможной.
Декартово дерево (treap)
Декартово дерево сочетает свойства бинарного дерева поиска и кучи, используя случайные приоритеты. Оно не требует явных поворотов для балансировки, но его высота в среднем \( O(\log n) \), а в худшем случае — \( O(n) \). АВЛ-дерево гарантирует логарифмическую высоту в любом случае.
B-деревья
B-деревья предназначены для работы с данными на дисках и имеют большую степень ветвления. АВЛ-деревья, как и другие бинарные деревья, эффективны в оперативной памяти, но не оптимизированы для блочного ввода-вывода.
Применение
АВЛ-деревья используются в системах, где требуется высокая скорость поиска при частых вставках и удалениях, а также в приложениях с жёсткими требованиями к времени выполнения операций. Примеры:
- Базы данных (в оперативной памяти, например, в некоторых реализациях индексов).
- Компиляторы (для хранения таблиц символов).
- Операционные системы (для управления памятью, например, в аллокаторах).
- Библиотеки алгоритмов (например, в стандартной библиотеке C++ контейнер
std::setиstd::mapчасто реализуются на основе красно-чёрных деревьев, но в некоторых реализациях используются АВЛ-деревья). - Графические редакторы (для хранения слоёв и объектов).
Реализация
Реализация АВЛ-дерева обычно включает структуру узла, содержащую ключ, значение, указатели на левого и правого потомков, а также высоту (или коэффициент сбалансированности). Основные функции:
insert(node, key)— вставка с рекурсивной балансировкой.delete(node, key)— удаление с рекурсивной балансировкой.search(node, key)— поиск.rotate_left(node)иrotate_right(node)— повороты.balance(node)— проверка и применение необходимого поворота.
Пример рекурсивной вставки на псевдокоде:
`` function insert(node, key): if node is None: return new_node(key) if key < node.key: node.left = insert(node.left, key) else: node.right = insert(node.right, key) node.height = 1 + max(height(node.left), height(node.right)) return balance(node) ``
Интересные факты
- Название «АВЛ» происходит от первых букв фамилий авторов (Адельсон-Вельский, Ландис). В западной литературе часто используется аббревиатура AVL.
- В оригинальной работе 1962 года авторы не использовали термин «вращение»; они описывали балансировку как «перестройку» дерева.
- АВЛ-дерево было первой самобалансирующейся структурой данных, для которой была доказана логарифмическая высота.
- В 1965 году Адельсон-Вельский и Ландис получили премию Академии наук СССР за эту работу.
Источники
- Адельсон-Вельский Г. М., Ландис Е. М. Алгоритм организации информации // Доклады АН СССР. — 1962. — Т. 146, № 2. — С. 263–266.
- Кормен Т., Лейзерсон Ч., Ривест Р., Штайн К. Алгоритмы: построение и анализ. — 3-е изд. — М.: Вильямс, 2013. — 1328 с. — ISBN 978-5-8459-1794-2.
- Седжвик Р. Фундаментальные алгоритмы на C++. — М.: ДиаСофт, 2002. — 688 с. — ISBN 5-93772-047-4.
- Кнут Д. Э. Искусство программирования. Том 3. Сортировка и поиск. — 2-е изд. — М.: Вильямс, 2007. — 832 с. — ISBN 978-5-8459-1314-2.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →