Раздел «Алгоритмы».DecartTrees:

Декартовые деревья

Содержание

Определение декартового дерева

Декартово дерево — это двоичное дерево, в узлах которого хранятся:

которое являются двоичным деревом поиска по ключу x и двоичной кучей по ключу y. А именно, для любого узла дерева n,

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

Простейший алгоритм построения декартового дерева. Свойство однозначности структуры

Простейший алгоритм построения декартового дерева (для понимания, а не для реализации) из данных пар (x, y) выглядит следующим образом. Упорядочим все пары по ключу x и пронумеруем получившуюся последовательность ключей y:

y(1), y(2), y(3), ..., y(n).

Найдём минимальный ключ y. Пусть это будет y(k). Он будет корнем дерева. Ключ y(k) делит последовательность ключей y на две:

y(1),..., y(k-1) ; y(k+1), ..., y_n.

В каждой из них найдём минимальный y — это будут дети узла y(k) — левый и правый. С получившимися 4 кусочками (возможно меньше) поступим аналогичным образом. Предложенный алгоритм построения декартового дерева основан на рекурсии:

Схематически это можно записать так:

 T( y(1), ..., y(n) ) =  root: y(k)   
                            left_tree: T( y(1),...,y(k-1) )   
                            right_tree: T( y(k+1)...y(n)) )
                         where  y(k) = min( y(1), ..., y(n) )

Из данного алгоритма следует, что множество пар (x, y) однозначно определяет структуру декартового дерева. Заметим для сравнения, что множество ключей, которые хранятся в двоичном дерево поиска не определяют однозначно структуру дерева. То же самое касается двоичной кучи — какова будет структура двоичной кучи (как ключи распределятся по улам) зависит не только от самого множества ключей, но и от последовательности их добавления. В декатртовом дереве такой неоднозначности нет.

Линейный алгоритм построения дерева

Другой алгоритм построения дерева также основан на рекурсии. Только теперь мы последовательно будем добавлять элементы y и перестраивать дерево. Дерево T( y(1), ..., y(k+1) ) будет строится из дерева T( y(1), ..., y(k) ) и следующего элемента y(k+1).

 T( y(1), ..., y(k+1) ) = F ( T( y(1),...,y(k) ) , y(k+1) )

На каждом шаге будем помнить ссыку на самый последний добавленный узел. Он будет самым правым. Действительно, мы упорядочили ключи y по прикреплённому к ним ключу x. Так как декартово дерево — это дерево поиска, то после проекции на горизонтальную прямую ключи x должны возрастать слева направо. Самый правый узел всегда имеет максимально возможное значение ключа x.

Функция F, которая отображает декартово дерево T( y(1),...,y(k) ) предыдущего шага и очередное y(k+1) в новое дерево T( y(1), ..., y(k+1) ) выгладит следующим образом. Вертикаль для узла y(k+1) определена. Нам необходимо определится с его горизонталью. Для начала мы проверяем, можно ли новый узел y(k+1) сделать правым ребёнком узла y(k) — это следует сделать если y(k+1) > y(k). Иначе мы делаем шаг по склону от узла y(k) вверх и смотрим на значение y, которое там хранится. Поднимаемся вверх по склону, пока не найдём узел, в котором значение y меньше, чем y(k+1), после чего делаем y(k+1) его правым ребёнком, а его предыдущего правого ребёнка делаем левым ребёнком узла y(k+1).

Это алгоритм амортизационно (в сумме за все шаги) работает линейное по числу добавляемых узлов время. Действительно, как только мы "перешагнули" через какой-либо узел, поднимаясь вверх по "склону", то мы его уже никогда не встретим при добавлении следующих узлов. Таким образом суммарное число шагов вверх по склону не может быть больше общего числа узлов.

-- ArtemVoroztsov - 02 Aug 2006

AlgorithmClasifyForm
Type: Теория
Scope: Структуры данных
Strategy:  
Complexity: High