Декартово дерево — различия между версиями
(→Split) |
(→Merge) |
||
| Строка 71: | Строка 71: | ||
<tex>T</tex> совпадёт с левым поддеревом <tex>T_1</tex>. Справа же нужно подвесить объединение правого поддерева | <tex>T</tex> совпадёт с левым поддеревом <tex>T_1</tex>. Справа же нужно подвесить объединение правого поддерева | ||
<tex>T_1</tex> и дерева <tex>T_2</tex>. | <tex>T_1</tex> и дерева <tex>T_2</tex>. | ||
| + | |||
| + | Псевдокод: | ||
| + | <pre> | ||
| + | Treap T // результат процедуры Merge | ||
| + | Treap T1, T2 // сливаемые деревья | ||
| + | |||
| + | Merge (Treap T, Treap T1, Treap T2) { | ||
| + | if (T1 == NULL || T2 == NULL) { | ||
| + | if (T1 != NULL) { | ||
| + | T = T1 | ||
| + | } | ||
| + | else { | ||
| + | T = T2 | ||
| + | } | ||
| + | } | ||
| + | else if (T1.y > T2.y) { | ||
| + | Merge (T1.right, T1.right, T2) | ||
| + | T = T1 | ||
| + | } | ||
| + | else { | ||
| + | Merge (T2.left, T1, T2.left) | ||
| + | T = T2 | ||
| + | } | ||
| + | } | ||
| + | </pre> | ||
Рассуждая аналогично операции <tex>\mathrm{Split}</tex> приходим к выводу, что трудоёмкость операции <tex>\mathrm{Merge}</tex> | Рассуждая аналогично операции <tex>\mathrm{Split}</tex> приходим к выводу, что трудоёмкость операции <tex>\mathrm{Merge}</tex> | ||
Версия 00:15, 15 апреля 2012
Эта статья про Курево
Декартово дерево — это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу (отсюда и второе её название: treap (tree + heap) и дерамида (дерево + пирамида), так же существует название курево (куча + дерево).
Более строго, это бинарное дерево, в узлах которого хранится пары , где - это ключ, а - это приоритет. Также оно является двоичным деревом поиска по и пирамидой по . Предполагая, что все и все являются различными, получаем, что если некоторый элемент дерева содержит , то у всех элементов в левом поддереве , у всех элементов в правом поддереве , а также и в левом, и в правом поддереве имеем: .
Дерамиды были предложены Сиделем (Siedel) и Арагоном (Aragon) в 1996 г.
Содержание
Операции в декартовом дереве
Split
Операция (разрезать) позволяет сделать следующее: разрезать декартово дерево по ключу и получить два других декартовых дерева: и , причем в находятся все ключи дерева , не большие , а в — большие .
.
Эта операция устроена следующим образом.
Рассмотрим случай, в котором требуется разрезать дерево по ключу, большему ключа корня. Посмотрим, как будут устроены результирующие деревья и :
- : левое поддерево совпадёт с левым поддеревом . Для нахождения правого поддерева , нужно разрезать правое поддерево на и по ключу и взять .
- совпадёт с .
Случай, в котором требуется разрезать дерево по ключу, меньше либо равному ключа в корне, рассматривается симметрично.
Псевдокод:
Treap T // декартово дерево
Node k // ключ по которому нужно разрезать декартово дерево
Split (Treap T, Node k, Treap T1, Treap T2) { // T1, T2 - результат процедуры Split
if (T == NULL) {
T1 = T2 = NULL
}
else if (k.x > T.x) {
Split (T.right, k, T.right, T2)
T1 = T
}
else {
Split (T.left, k, T1, T.left)
T2 = T
}
}
Оценим время работы операции . Во время выполнения вызывается одна операция для дерева хотя бы на один меньшей высоты и делается ещё операция. Тогда итоговая трудоёмкость этой операции равна , где — высота дерева.
Merge
Рассмотрим вторую операцию с декартовыми деревьями — (слить).
С помощью этой операции можно слить два декартовых дерева в одно. Причем, все ключи в первом(левом) дереве должны быть меньше, чем ключи во втором(правом). В результате получается дерево, в котором есть все ключи из первого и второго деревьев.
Рассмотрим принцип работы этой операции. Пусть нужно слить деревья и . Тогда, очевидно, у результирующего дерева есть корень. Корнем станет вершина из или с наибольшим ключом . Но вершина с самым большим из всех вершин деревьев и может быть только либо корнем , либо корнем . Рассмотрим случай, в котором корень имеет больший , чем корень . Случай, в котором корень имеет больший , чем корень , симметричен этому.
Если корня больше корня , то он и будет являться корнем. Тогда левое поддерево совпадёт с левым поддеревом . Справа же нужно подвесить объединение правого поддерева и дерева .
Псевдокод:
Treap T // результат процедуры Merge
Treap T1, T2 // сливаемые деревья
Merge (Treap T, Treap T1, Treap T2) {
if (T1 == NULL || T2 == NULL) {
if (T1 != NULL) {
T = T1
}
else {
T = T2
}
}
else if (T1.y > T2.y) {
Merge (T1.right, T1.right, T2)
T = T1
}
else {
Merge (T2.left, T1, T2.left)
T = T2
}
}
Рассуждая аналогично операции приходим к выводу, что трудоёмкость операции равна , где — высота дерева.
Insert
Операция добавляет в дерево элемент , где — ключ, а — приоритет.
- Реализация №1
- Разобьём наше дерево по ключу, который мы хотим добавить, то есть .
- Сливаем первое дерево с новым элементом, то есть .
- Сливаем получившиеся дерево со вторым, то есть .
- Реализация №2
- Сначала спускаемся по дереву (как в обычном бинарном дереве поиска по ), но останавливаемся на первом элементе, в котором значение приоритета оказалось меньше .
- Теперь вызываем от найденного элемента (от элемента вместе со всем его поддеревом)
- Полученные и записываем в качестве левого и правого сына добавляемого элемента.
- Полученное дерево ставим на место элемента, найденного в первом пункте.
Remove
Операция удаляет из дерева элемент с ключом .
- Реализация №1
- Разобьём наше дерево по ключу, который мы хотим удалить, то есть .
- Теперь отделяем от первого дерева элемент , опять таки разбивая по ключу , то есть .
- Сливаем первое дерево со вторым, то есть .
- Реализация №2
- Спускаемся по дереву (как в обычном бинарном дереве поиска по ), ища удаляемый элемент.
- Найдя элемент, вызываем его левого и правого сыновей
- Возвращаемое значение функции ставим на место удаляемого элемента.
Случайные ключи
Мы уже выяснили, что сложность операций с декартовым деревом линейно зависит от его высоты. В действительности высота декартова дерева может быть линейной относительно его размеров. Например, высота декартова дерева, построенного по набору ключей , будет равна . Во избежание таких случаев, полезным оказывается выбирать приоритеты в ключах случайно.
Высота в декартовом дереве
| Теорема: | ||||||
Декартово дерево из узлов, ключи которых являются независимыми случайными величинами одного и того же распределения, имеет высоту . | ||||||
| Доказательство: | ||||||
|
Для начала введем несколько обозначений:
В силу обозначений глубину вершины можно записать как количество предков:
Теперь можно выразить математическое ожидание глубины конкретной вершины:
Для подсчёта средней глубины вершин нам нужно сосчитать вероятность того, что вершина является предком вершины , то есть . Введем новое обозначение:
Так как каждая вершина среди может иметь минимальный приоритет, мы немедленно приходим к следующему равенству: Подставив последнее в нашу формулу с математическим ожиданием получим: | ||||||