- •1. Введение
- •2. Структура данных
- •3. Операции
- •3.1. Поиск
- •3.2. Вставка
- •3.3. Удаление
- •3.4. Замечания
- •[ Править ]Теория
- •[ Править ]Операции [ править ]Вставка
- •[ Править ]Набросок доказательства по стоимости вставка
- •[ Править ]Удаление
- •[ Править ]Набросок доказательства на стоимость удаления
- •[ Править ]Lookup
Дерево со штрафами (scapegoat tree)
1. Введение
Бинарное дерево поиска называется сбалансированным по весу, если половина узлов находится слева от корня, а вторая – справа. Деревья называются α-weight-сбалансированными, если они отвечают следующим условиям:
size(left) <= α*size(node)size(right) <= α*size(node)
Где функция size может быть определена рекурсивно:
function size(node)begin
if node = nil
return 0;
else
return size(node->left) + size(node->right) + 1;
end;
Бинарное дерево поиска, которое является α-weight-сбалансированный также должны быть α-height-сбалансированный, то есть
height(root) <= log1/α(size(root))
Деревом со штрафами называют самобалансирующееся бинарное дерево поиска, изобретенное Игалем Гальперини (Igal Galperin), Яковом Tepecом (Jacob Teres) и Рональдом Ривестом (Ronald L. Rivest). Оно обеспечивает в худшем случае время поиска O(log n), и амартизированное время вставки и удаления O(log n).
В отличие от большинства других самобалансирующихся двоичных деревьев поиска, которые обеспечивают наихудшее время поиска O (log n), деревья со штрафами не имеют дополнительных расходов памяти (как, например, цвет или вес) по сравнению с обычными бинарными деревьями поиска: узел хранит только ключ и два указателя на дочерние узлы. Корень дерева имеет только 2 дополнительных значения – число узлов всего дерева и максимальное число узлов в дереве с момента последней перестройки. Это делает деревья со штрафами проще в реализации и может уменьшить накладные расходы узла до одной трети.
Коэффициент 0 < α < 0.5 «жесткости» дерева можно задавать произвольно и высота дерева будет ограничена сверху значением k*log(n)+1, где k=log2(1/α)
Коэффициент жесткости сильно влияет на баланс производительности: чем «жестче» дерево, тем меньше у него будет высота и тем быстрее будет работать поиск, но тем сложнее будет поддерживать порядок в операциях модификации. Например, так как АВЛ-дерево «жестче» красно-черного, поиск в нем работает быстрее, а модификация медленней. Если же пользоваться scapegoat-деревом, баланс между этими операциями можно выбирать в зависимости от специфики применения дерева.
В дереве со штрафами операция балансировки начинают с листа и последовательно рассматривают вверх всех предков до узла (называемого “козлом отпущения” – scapegoat), которое настолько несбалансированное, что все поддерево с корнем в этом узле может быть перестроено по нулевой стоимости, в амортизированной смысле. Отсюда и название.
Деревья со штрафами не гарантирует сохранение α-weight-баланса в любое время, но всегда α-height-баланс, так как
height(scapegoat tree) <= log1/α(size(root)) + 1
2. Структура данных
Дерево со штрафами состоит из обычных бинарных деревьев поиска, с двумя дополнительными значениями, хранящимися в корне.
Каждый узел x из дерева «козла отпущения» содержит следующие атрибуты:
key [x] – ключ, хранящийся в узле x.
left [x] – левый потомок x.
right [x] – правый потомок x.
Мы будем также использовать обозначения:
size (x) – размер поддерева с корнем в x (т. е. число ключей, хранящихся в этом поддереве, в том числе ключ, хранящийся в x).
brother (x) – брат узла x (другой потомок предка x или NIL)
h(x) и h(T) – высота узла и дерева соответственно. Высота узла это длина самого длинного пути от этого узла до листьев. Высота дерева это высота его корня.
d(x) – глубина узла x. Глубина узла это длина (число ребер) пути от корня до этого узла (Корневой узел имеет глубину 0).
Обратите внимание, что на самом деле в узлах хранятся первые три параметра: : key, left и right, а остальные данные вычисляются как функции.
Вычисление brother(x) требует знание предков x. Самое главное, size(x) не хранится в x, но может быть вычислено за время O(log n) при необходимости.
Дерево T в целом имеет следующие атрибуты:
root [T] – указатель на корневой узел дерева.
size[T] – количество узлов в дереве. Это тоже самое, что size(root[T]). В нашем анализе мы также будем обозначать size[T] как n.
max_size[T] – максимальное значение size[T] с момента последней перестройки дерева. Если операция удаления не поддерживается, то в атрибуте max_size нет необходимости