Tango-дерево
Танго дерево Поиск Перестройка дерева
Содержание
Динамическая оптимальность
Гипотеза: |
Splay деревья обладают динамической оптимальностью.
То есть если мы разрешаем перестраивать деревья в процессе запроса, то splay-деревья не больше, чем в константу хуже оптимальных. Время работы splay дерева |
Модель оптимального дерева
Рассмотрим ключи
и запросы , где – ключ, к которому мы обращаемся.Утверждение: |
Существует гипотетически оптимальное дерево, которое на каждый запрос делает следующие вещи
|
Оценка снизу на динамический оптимум
Визуализация работы с гипотетически оптимальным динамическим двоичным деревом поиска
Рассмотрим систему координат ключ -- время. Поставим точки, которые соответствуют обращению по данному ключу в определенное время.
Множество точек определяет, что происходило с деревом.
Определение: |
Множество точек называется древесным (aboral), если выполняется следующее свойство: возьмем произвольный невырожденный прямоугольник(площадь прямоугольника больше нуля) с углами в наших точках. |
Утверждение: |
Множество точек удовлетворяет свойству древесности, если на любом прямоугольнике с вершинами в наших точках есть еще хотя бы одна точка, отличная от точек, на которых его построили. |
Теорема: |
Множество точек является фазовой диаграммой работы с некоторым деревом поиска тогда и только тогда, когда оно обладает свойством древесности. |
Доказательство: |
1. Фазовая диаграмма работы с деревом поиска обладает свойством древестности. Пусть мы обращались к какому-то ключу в -ом запросе и к какому-то ключу в -ом запросе. Рассмотрим этот прямоугольник. На момент -го запроса рассмотрим в дереве поиска наименьшего общего предка и -- вершину .Если , то все хорошо, значит в дереве поиска она находится между и , поэтому мы к нему обращались в то время, когда шли к , значит есть точка на стороне нашего многоугольника.Если , то есть -- предок в момент -го запроса, тогда рассмотрим момент -го запроса, когда мы обращались к .Найдем в дереве поиска наименьшего общего предка вершин и на момент -го запроса.Если , тогда мы к нему обращались, и есть точка на стороне нашего прямоугольника.Если , то есть - предок в момент -го запроса, Значит «всплывал», и хотя бы раз, между этими моментами выполнялся поворот вокруг ребра от к родителю.То есть во время -го запроса был в поддереве , а во время -го запроса в поддереве , значит где-то между этими моментами выполнялся поворот вокруг ребра от к родителю, и мы обращались к , следовательно есть точка на правой стороне нашего прямоугольника.(рисунок надо?) 2. Если множество точек обладает свойством древесности, то оно является фазовой диаграммой работы с некоторым деревом поиска. Для любого прямоугольника, построенного на наших точках, есть еще одна точка на стороне. Докажем, что можно построить такое дерево, для которого наши точки будут соответствовать запросам. Рассмотрим наше множество точек. Построим из них декартово(!) дерево, где ключом будет ключ, а вспомогательным ключом – время, когда мы следующий раз обратимся к вершине, то есть для каждого найдем минимальный такой, что существует точкаПриоритет будет меняться по мере того, как мы будет симулировать работу с деревом поиска.
Есть очередная горизонталь, на которой есть точки. Они по построению в текущий момент имеют минимальный приоритет, поэтому как-то организованы в районе корня нашего декартового дерева. Обойдем эти точки. После этого мы должны перестроить наше дерево, изменив приоритеты. Утверждается, что выполняя повороты только внутри верхней части нашего дерево можно построить дерево в соответствии с новыми приоритетами. Почему? Предположим, что это не удалось сделать. У нас есть вершина , у которой есть правый сын , и приоритет больше чем у , их надо поменять, то есть дотронуться до вершины , чего мы делать не хотели в этой строке.Но тогда рассмотрим прямоугольник(мы обращались к )А когда-то мы обратимся к Если есть точка на левой стороне, то к мы обратимся раньше, чем к следовательно неверно, что приоритет больше чем приоритетНа левой стороне точек нет. Если на нижней стороне есть точка, значит есть точка, к которой мы обращались сейчас, ключ которой больше, чем у , но меньше , но тогда она должна быть нашим правым сыном, а не вершина .Если на правой стороне есть точка, то сейчас мы бы обращались к ней, а не к .Если на верхней стороне есть точка с ключом меньше , мы будем обращаться к ней тогда же, когда и к , значит мы может перейти к прямоугольнику, построенному на точках и .Когда таких точек (как Поэтому при перестроении декартова дерева нам не потребуется переходить из нашей верхней зоны. ) не останется, то мы получим прямоугольник, у которого нет точек на всех сторонах, а это противоречит исходному условию. |
Таким образом, мы получили какую-то offline оптимальность.
Рассмотрим наши запросы, отметим их точками, тогда время работы оптимального динамического дерева равно количество точек на диаграмме.
Получим нижнюю оценку на оптимум.
Если что-то работает за , значит это работает не более, чем в раз хуже.Рассмотрим запросы.
Покроем их независимыми прямоугольниками.
Прямоугольники независимы, если угол одного не лежит внутри другого.
Можно показать, что
(число запросов) + максимальное число независимых прямоугольников * 1/2Вторая нижняя оценка Уилберра (Wilber)
Для каждого запроса
вычислим число Уилберра.Для ключа
рассмотрим ключиПусть
, где и -- левая и правая границы на момент i. Будем передвигать левую границу каждый раз, когда встречаем число . Аналогично правую. В каждый момент времени позиция может увеличиваться, уменьшаться.Напишем
, если изменяется правая граница и - если левая.Числом Уилберра
называется количество смен на и обратно.Получаем следующую оценку
Теорема: |
Рассмотрим ключей и запросов запросы
Организуем их в полное двоичное сбалансированное дерево. Будем в этом дереве искать наши ключи в том порядке, в котором их искали в оптимальное дереве. Для каждой вершины будем запоминать ребро, по которому мы последний раз проходили при поиске ключей в дереве(назовем его жирное ребро). Утверждается, что То есть если мы улучшили правую границу(мы искали что-то справа), а потом улучшили левую(искали слева), значит где-то по пути мы прошли туда-обратно и сменили жирное ребро. >= изменения числа жирных ребер. |
Tango-деревья
Определение: |
Танго дерево - online бинарное дерево поиска с временем работы | , которое изобрели Эрик Д. Демейн, Дион Хармон, Джон Яконо и Mihai Patrascu в 2004 году. Лучшая известная реализация на данный момент.
Время работы tango дерева
Построение
Определение: |
Жирное ребро(Prefered Path) - ребро, соединяющее вершину с ее последним посещенным ребенком. |
Рассмотрим бинарное дерево поиска.
Изначально сделаем все левые ребра жирными.
Разобьем наше дерево на жирные пути.
Каждый из этих жирных путей организуем в свое splay-дерево.
Из каждой вершины создадим вспомогательную ссылку на корень splay дерева, соответствующего жирному пути, в котором лежит тот ее ребенок, в который ведет из нее нежирное ребро.
Таким образом, все наши ключи организуют иерархичную структуру -- Tango дерево.
Каждый жирный путь -- splay дерево, и каждое их них указывает на корень дерева, в котором лежит ее второй сын(при этом указатель ставится на само дерево, а не на сына).
Глубина tango дерева
.Время работы (M + число изменений жирных ребер) *
Операций первого становления ребра жирным -- O(log n), это дает несущественный вклад в асимптотику.
Поиск
Поиск элемента в
дереве схож с поиском в обычном дереве поиска.Начинаем с поиска в жирном пути корня
дерева –- дереве.Если текущий жирный путь не содержит искомый элемент, то сделаем переход по вспомогательной ссылке(красная стрелка) и осуществим поиск в новом жирном пути(
дереве).Поиск в
дереве(синем) дереве = высота от количества вершин (количество вершин = длине жирного пути = ) = .Поиск во всем дереве =
* число проходов по нежирному ребру.Пример
Перестройка дерева
Для того, чтобы сохранить структуру
дерева ( дерево соответствует текущему жирному пути), мы должны обновлять его каждый раз, когда жирные ребра изменяются в результате поиска. После изменения жирного ребра верхняя часть жирного пути отделяется от нижней части (которая становится самостоятельным жирным путем) и присоединяется к другому жирному пути (который становится нижней частью).Во-первых, мы должны запомнить для каждой вершины нашего изначального дерева поиска дополнительную информацию:
-- минимальное значение в поддереве текущей вершины, -- максимальное значение в поддереве.Во-вторых, нам понадобятся операции split и merge, которые работают за
, где - число узлов в дереве.Пусть для того, чтобы найти вершину
, которая находится в дереве , мы прошли по тонкому ребру из вершины , находящейся в дереве . Значит, нам нужно объединить деревья и и вырезать из дерева подддерево , в которое ведет жирное ребро из вершины .Пусть поддерево
-- правое. Для левого аналогично.- Так как мы знаем интервал значений вершины в ее правом поддереве , сделаем по концам отрезка две операции . Теперь мы можем отрезать поддерево .
- Все ключи дерева меньше (так как бинарное дерево поиска), поэтому выполним операцию по максимальному значению , меньшему .
- Выполним операцию merge деревьев и .
- Выполним операцию merge деревьев и .
- Выполним операцию merge деревьев и .
- Проведем тонкое ребро от вершины к дереву .
Таким образом, перестройка =
, каждый из них за * число изменений жирного ребра.