Декартово дерево — различия между версиями
(→Высота декартового дерева) |
(→Высота в декартовом дереве) |
||
Строка 93: | Строка 93: | ||
Для начала введем несколько обозначений: | Для начала введем несколько обозначений: | ||
− | * <tex>x_k</tex> - вершина с <tex>k</tex>-ым по величине ключом; | + | * <tex>x_k</tex> {{---}} вершина с <tex>k</tex>-ым по величине ключом; |
+ | * индикаторная величина <tex>A_{i, j} = \left\{\begin{array}{lllc} 1 &&, x_i\ -\ \text{ancestor} \ x_j\\ | ||
+ | 0 &&, \text{otherwise}\\ | ||
+ | \end{array}\right. | ||
+ | </tex> | ||
+ | * <tex>d(v)</tex> - глубина вершины <tex>v</tex>; | ||
+ | |||
+ | В силу обозначений глубину вершины можно записать как количество предков: | ||
+ | :<tex>d(x_k) = \sum\limits_{i = 1}^{n} A_{i,k} </tex>. | ||
+ | |||
+ | Теперь можно выразить математическое ожидание глубины конкретной вершины: | ||
+ | :<tex>E(d(x_k)) = \sum\limits_{i = 1}^{n} Pr[A_{i,k} = 1] </tex> {{---}} здесь мы использовали линейность математического ожидания <tex>E</tex>, и то что <tex>E(X) = Pr[X = 1]</tex> для индикаторной величины <tex>X</tex> (<tex>Pr[A]</tex> {{---}} вероятность события <tex>A</tex>). | ||
+ | Для подсчёта средней глубины вершин нам нужно сосчитать вероятность того, что вершина <tex>x_i</tex> является предком вершины <tex>x_k</tex>, то есть <tex>Pr[A_{i,k} = 1]</tex>. | ||
+ | |||
+ | Введем новое обозначение: | ||
+ | * <tex>X_{i, k}</tex> {{---}} множество ключей <tex>\{x_i, \ldots, x_k\}</tex> или <tex>\{x_k, \ldots, x_i\}</tex>, в зависимости от <tex>i < k</tex> или <tex>i > k</tex>. <tex>X_{i, k}</tex> и <tex>X{k, i}</tex> обозначают одно и тоже, их мощность равна <tex>|k - i| + 1</tex>. | ||
+ | |||
+ | {{Лемма | ||
+ | |statement=Для любых <tex>i \ne k</tex> , <tex>x_i</tex> является предком <tex>x_k</tex> тогда и только тогда, когда <tex>x_i</tex> имеет наименьший приоритет среди <tex>X_{i, k}</tex>. | ||
+ | |proof=Если <tex>x_i</tex> является корнем, то оно является предком <tex>x_k</tex> и по определению имеет минимальный приоритет среди всех вершин, следовательно, и среди <tex>X_{i, k}</tex>. | ||
+ | |||
+ | С другой стороны, если <tex>x_k</tex> {{---}} корень, то <tex>x_i</tex> {{---}} не предок <tex>x_k</tex>, и <tex>x_k</tex> имеет минимальный приоритет в treap’е; следовательно, <tex>x_i</tex> не имеет наименьший приоритет среди <tex>X_{i, k}</tex>. | ||
+ | |||
+ | Теперь предположим, что какая-то другая вершина <tex>x_m</tex> – корень. Тогда, если <tex>x_i</tex> и <tex>x_k</tex> лежат в разных поддеревьях, то <tex>i < m < k</tex> или <tex>i > m > k</tex>, следовательно, <tex>x_m</tex> содержится в <tex>X_{i , k}</tex>. В этом случае <tex>x_i</tex> – не предок <tex>x_k</tex>, и наименьший приоритет среди <tex>X_{i, k}</tex> имеет вершина с номером <tex>m</tex>. | ||
+ | |||
+ | Наконец, если <tex>x_i</tex> и <tex>x_k</tex> лежат в одном поддереве, то доказательство применяется по индукции, так как это поддерево является меньшим treap’ом. Пустой treap есть тривиальная база. | ||
+ | }} | ||
+ | |||
+ | Так как каждая вершина среди <tex>X_{i, k}</tex> может иметь минимальный приоритет, мы немедленно приходим к следующему равенству: | ||
}} | }} | ||
Версия 21:31, 12 апреля 2012
Эта статья про Курево
Содержание
Описание
Декартово дерево — это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу (отсюда и второе её название: treap (tree + heap) и дерамида (дерево + пирамида), так же существует название курево (куча + дерево).
Более строго, это структура данных, которая хранит пары
в виде бинарного дерева таким образом, что она является бинарным деревом поиска по и бинарной пирамидой по . Предполагая, что все и все являются различными, получаем, что если некоторый элемент дерева содержит , то у всех элементов в левом поддереве , у всех элементов в правом поддереве , а также и в левом, и в правом поддереве имеем: .Дерамиды были предложены Сиделем (Siedel) и Арагоном (Aragon) в 1996 г.
Операции в декартовом дереве
Split
Операция
(разрезать) позволяет сделать следующее: разрезать декартово дерево по ключу и получить два других декартовых дерева: и , причем в находятся все ключи дерева , не большие , а в — большие ..
Эта операция устроена следующим образом.
Рассмотрим случай, в котором требуется разрезать дерево по ключу, большему ключа корня. Посмотрим, как будут устроены результирующие деревья
и :- : левое поддерево совпадёт с левым поддеревом . Для нахождения правого поддерева , нужно разрезать правое поддерево на и по ключу и взять .
- совпадёт с .
Случай, в котором требуется разрезать дерево по ключу, меньше либо равному ключа в корне, рассматривается симметрично.
Оценим время работы операции
. Во время выполнения вызывается одна операция для дерева хотя бы на один меньшей высоты и делается ещё операция. Тогда итоговая трудоёмкость этой операции равна , где — высота дерева.Merge
Рассмотрим вторую операцию с декартовыми деревьями —
(слить).С помощью этой операции можно слить два декартовых дерева в одно. Причем, все ключи в первом(левом) дереве должны быть меньше, чем ключи во втором(правом). В результате получается дерево, в котором есть все ключи из первого и второго деревьев.
Рассмотрим принцип работы этой операции. Пусть нужно слить деревья
и . Тогда, очевидно, у результирующего дерева есть корень. Корнем станет вершина из или с наибольшим ключом . Но вершина с самым большим из всех вершин деревьев и может быть только либо корнем , либо корнем . Рассмотрим случай, в котором корень имеет больший , чем корень . Случай, в котором корень имеет больший , чем корень , симметричен этому.Если
корня больше корня , то он и будет являться корнем. Тогда левое поддерево совпадёт с левым поддеревом . Справа же нужно подвесить объединение правого поддерева и дерева .Рассуждая аналогично операции
приходим к выводу, что трудоёмкость операции равна , где — высота дерева.Insert
Операция
добавляет в дерево элемент , где — ключ, а — приоритет.- Реализация №1
- Разобьём наше дерево по ключу, который мы хотим добавить, то есть .
- Сливаем первое дерево с новым элементом, то есть .
- Сливаем получившиеся дерево со вторым, то есть .
- Реализация №2
- Сначала спускаемся по дереву (как в обычном бинарном дереве поиска по ), но останавливаемся на первом элементе, в котором значение приоритета оказалось меньше .
- Теперь вызываем от найденного элемента (от элемента вместе со всем его поддеревом)
- Полученные и записываем в качестве левого и правого сына добавляемого элемента.
- Полученное дерево ставим на место элемента, найденного в первом пункте.
Remove
Операция
удаляет из дерева элемент с ключом .- Реализация №1
- Разобьём наше дерево по ключу, который мы хотим удалить, то есть .
- Теперь отделяем от первого дерева элемент , опять таки разбивая по ключу , то есть .
- Сливаем первое дерево со вторым, то есть .
- Реализация №2
- Спускаемся по дереву (как в обычном бинарном дереве поиска по ), ища удаляемый элемент.
- Найдя элемент, вызываем его левого и правого сыновей
- Возвращаемое значение функции ставим на место удаляемого элемента.
Случайные ключи
Мы уже выяснили, что сложность операций с декартовым деревом линейно зависит от его высоты. В действительности высота декартова дерева может быть линейной относительно его размеров. Например, высота декартова дерева, построенного по набору ключей
, будет равна . Во избежание таких случаев, полезным оказывается выбирать приоритеты в ключах случайно.Высота в декартовом дереве
Теорема: | ||||||
Декартово дерево из узлов, ключи которых являются незавимыми непрерывными случайными величинами с одинаковым вероятностным распределением, имеет высоту . | ||||||
Доказательство: | ||||||
Для начала введем несколько обозначений:
В силу обозначений глубину вершины можно записать как количество предков:
Теперь можно выразить математическое ожидание глубины конкретной вершины:
Для подсчёта средней глубины вершин нам нужно сосчитать вероятность того, что вершина является предком вершины , то есть .Введем новое обозначение:
| ||||||