Декартово дерево — различия между версиями
(→Операция split) |
|||
Строка 10: | Строка 10: | ||
[[file:split.png|thumb|200px|Операция split]] | [[file:split.png|thumb|200px|Операция split]] | ||
− | Операция <tex>\mathrm{split}</tex>(''разрезать'') позволяет сделать следующее: разрезать декартово дерево <tex>T</tex> по ключу | + | Операция <tex>\mathrm{split}</tex> (''разрезать'') позволяет сделать следующее: разрезать декартово дерево <tex>T</tex> по ключу |
<tex>x</tex> и получить два других декартовых дерева: <tex>T_1</tex> и <tex>T_2</tex>, причем в <tex>T_1</tex> | <tex>x</tex> и получить два других декартовых дерева: <tex>T_1</tex> и <tex>T_2</tex>, причем в <tex>T_1</tex> | ||
находятся все ключи дерева <tex>T</tex>, не большие <tex>x</tex>, а в <tex>T_2</tex> {{---}} большие <tex>x</tex>. | находятся все ключи дерева <tex>T</tex>, не большие <tex>x</tex>, а в <tex>T_2</tex> {{---}} большие <tex>x</tex>. | ||
Строка 16: | Строка 16: | ||
<tex>\mathrm{split}(T, x) \to \{T_1, T_2\}</tex>. | <tex>\mathrm{split}(T, x) \to \{T_1, T_2\}</tex>. | ||
− | + | Эта операция устроена следующим образом. | |
Рассмотрим случай, в котором требуется разрезать дерево по ключу, большему ключа корня. | Рассмотрим случай, в котором требуется разрезать дерево по ключу, большему ключа корня. | ||
Строка 33: | Строка 33: | ||
[[file:merge.png|thumb|200px|Операция merge]] | [[file:merge.png|thumb|200px|Операция merge]] | ||
− | Рассмотрим вторую | + | Рассмотрим вторую операцию с декартовыми деревьями {{---}} <tex>\mathrm{merge}</tex>(''слить''). |
− | С помощью этой операции можно | + | С помощью этой операции можно слить два декартовых дерева в одно. |
− | + | Причем, все ключи в первом(''левом'') дереве должны быть меньше, чем | |
− | ключи во втором(''правом'') | + | ключи во втором(''правом''). В результате получается дерево, в котором есть все ключи из первого и второго деревьев. |
<tex>\mathrm{merge}(T_1, T_2) \to T</tex> | <tex>\mathrm{merge}(T_1, T_2) \to T</tex> | ||
Строка 43: | Строка 43: | ||
Рассмотрим принцип работы этой операции. Пусть нужно слить деревья <tex>T_1</tex> и <tex>T_2</tex>. | Рассмотрим принцип работы этой операции. Пусть нужно слить деревья <tex>T_1</tex> и <tex>T_2</tex>. | ||
Тогда, очевидно, у результирующего дерева <tex>T</tex> есть корень. | Тогда, очевидно, у результирующего дерева <tex>T</tex> есть корень. | ||
− | + | Корнем станет самая высокая из вершин <tex>T_1</tex> и <tex>T_2</tex>. Но самая высокая вершина из всех вершин деревьев | |
− | |||
<tex>T_1</tex> и <tex>T_2</tex> может быть только либо корнем <tex>T_1</tex>, либо корнем <tex>T_2</tex>. | <tex>T_1</tex> и <tex>T_2</tex> может быть только либо корнем <tex>T_1</tex>, либо корнем <tex>T_2</tex>. | ||
Рассмотрим случай, в котором корень <tex>T_1</tex> выше корня <tex>T_2</tex>. | Рассмотрим случай, в котором корень <tex>T_1</tex> выше корня <tex>T_2</tex>. |
Версия 20:50, 17 мая 2011
Эта статья про Курево
Декартово дерево — это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу (отсюда и второе её название:
и дерамида (дерево+пирамида).Более строго, это структура данных, которая хранит пары
в виде бинарного дерева таким образом, что она является бинарным деревом поиска по и бинарной пирамидой по . Предполагая, что все и все являются различными, получаем, что если некоторый элемент дерева содержит , то всех элементов в левом поддереве , у всех элементов в правом поддереве , а также и в левом, и в правом поддереве имеем: .Дерамиды были предложены Сиделем (Siedel) и Арагоном (Aragon) в 1996 г.
Содержание
Операция split
Операция
(разрезать) позволяет сделать следующее: разрезать декартово дерево по ключу и получить два других декартовых дерева: и , причем в находятся все ключи дерева , не большие , а в — большие ..
Эта операция устроена следующим образом.
Рассмотрим случай, в котором требуется разрезать дерево по ключу, большему ключа корня. Посмотрим, как будут устроены результирующие деревья
и :- : левое поддерево совпадёт с левым поддеревом . Для нахождения правого поддерева , нужно разрезать правое поддерево на и по ключу и взять .
- совпадёт с .
Случай, в котором требуется разрезать дерево по ключу, меньше либо равному ключа в корне, рассматривается симметрично.
Оценим время работы операции
. Во время выполнения вызывается одна операция для дерева хотя бы на один меньшей высоты и делается ещё операция. Тогда итоговая трудоёмкость этой операции равна , где — высота дерева. Так как высота декартова дерева — , то и операция работает за .Операция merge
Рассмотрим вторую операцию с декартовыми деревьями —
(слить).С помощью этой операции можно слить два декартовых дерева в одно. Причем, все ключи в первом(левом) дереве должны быть меньше, чем ключи во втором(правом). В результате получается дерево, в котором есть все ключи из первого и второго деревьев.
Рассмотрим принцип работы этой операции. Пусть нужно слить деревья
и . Тогда, очевидно, у результирующего дерева есть корень. Корнем станет самая высокая из вершин и . Но самая высокая вершина из всех вершин деревьев и может быть только либо корнем , либо корнем . Рассмотрим случай, в котором корень выше корня . Случай, в котором корень выше корня , симметричен этому.Если корень
выше корня , то он и будет являться корнем. Тогда левое поддерево совпадёт с левым поддеревом . Справа же нужно подвесить объединение правого поддерева и дерева .Рассуждая аналогично операции
приходим к выводу, что трудоёмкость операции равна .Операция add
Операция
добавляет в дерево элемент , где — ключ, а — приоритет.Реализация №1:
- Разобьём наше дерево по ключу, который мы хотим добавить, то есть .
- Сливаем первое дерево с новым элементом, то есть .
- Сливаем получившиеся дерево со вторым, то есть .
Реализация №2:
Сначала спускаемся по дереву (как в обычном бинарном дереве поиска по
), но останавливаемся на первом элементе, в котором значение приоритета оказалось меньше . Мы нашли позицию, куда будем вставлять наш элемент. Теперь вызываем от найденного элемента (от элемента вместе со всем его поддеревом), и возвращаемые ею и записываем в качестве левого и правого сына добавляемого элемента.
Операция remove
Операция
удаляет из дерева элемент с ключом .Реализация №1:
- Разобьём наше дерево по ключу, который мы хотим удалить, то есть .
- Теперь отделяем от первого дерева элемент , опять таки разбивая по ключу , то есть .
- Сливаем первое дерево со втором, то есть .
Реализация №2:
Спускаемся по дереву (как в обычном бинарном дереве поиска по
), ища удаляемый элемент. Найдя элемент, мы просто вызываем его левого и правого сыновей, и возвращаемое ею значение ставим на место удаляемого элемента, то есть .