Изменения

Перейти к: навигация, поиск

Левосторонняя куча

283 байта добавлено, 16:52, 1 сентября 2014
Нет описания правки
Левосторонние деревья были изобретены Кларком Крейном (Clark Allan Crane), свое название они получили из-за того, что левое поддерево обычно длиннее правого.
{{Определение
|definition='''Левосторонняя куча ''' (англ. ''leftist heap)''' ) {{---}} двоичное левосторонее [[Дерево, эквивалентные определения|дерево]] (не обязательно сбалансированное), но с соблюдением [[Двоичная куча#Определение|порядка кучи]] (heap order).}}
'''Свободной позицией''' назовем место в дереве, куда может быть вставлена новая вершина. Само дерево будет являться свободной позицией, если оно не содержит вершин. Если же у какой-то внутренней вершины нет сына, то на его месте {{---}} ''свободная позиция''.
{{Лемма
{{Определение
|definition='''Условие левосторонней кучи'''. Пусть <tex>dist(u)</tex> {{---}} расстояние от вершины <tex>u</tex> до ближайшей свободной позиции в ее поддереве. У пустых позиций <tex>dist = 0</tex>. Тогда потребуем для любой вершины <tex>u : dist(u.Lleft)\geqslant dict(u.Rright)</tex>.}}
Если для какой- то вершины это свойство не выполняется, то это легко устраняется: можно за <tex>O(1)</tex> поменять местами левого и правого ребенка, что не повлияет на порядок кучи.
Слияние двух куч.
'''functionLeftistHeap''' merge(x, y): <font color=darkgreen>// x, y {{---}} корни двух деревьев</font> '''if''' x == <tex> \varnothing </tex>: '''return''' y '''if''' y == <tex> \varnothing </tex>: '''return''' x
'''if''' y.key < x.key:
swap(x, y)
<font color=darkgreen>// Воспользуемся тем, что куча левосторонняя. Правая ветка {{---}} самая короткая и не длиннее логарифма. // Пойдем направо и сольем правое поддерево с у.</font> x.R right = '''merge'''(x.Rright, y) <font color=darkgreen>// Могло возникнуть нарушение левостороннести кучи.</font> '''if''' dist(x.Rright) > dist(x.Lleft): swap(x.Lleft, x.Rright) dist(x) = min(dist(x.Lleft), dist(x.Rright)) + 1 <font color=darkgreen>// пересчитаем расстояние до ближайшей свободной позиции</font>
'''return''' x
<font color=darkgreen>// Каждый раз идем из уже существующей вершины только в правое поддерево {{---}} не более логарифма вызовов (по лемме)</font>
Левосторонняя куча относится к сливаемым кучам: остальные операции легко реализуются с помощью операции слияния.
Как и у любой другой двоичной кучи, минимум хранится в корне. Извлекаем минимальное значение, удаляем корень, сливаем левое и правое поддерево корня. Возвращает пару из извлеченной вершины и новой кучи.
===delete===
Аналогично удаляется любой элемент {{---}} на его место ставится результат слияния его детей. Но так просто любой элемент удалить нельзя {{---}} на пути от этого элемента к корню может нарушиться левостороннесть кучи. А до корня мы дойти не можем, так как элемент может находиться на линейной глубине. Поэтому удаление реализуется с помощью <tex>decrease key\mathrm{decreaseKey}</tex>. Уменьшаем ключ до <tex>-\infty</tex>, затем извлекаем минимальное значение.
===decreaseKey===
{{Лемма
|about=3
|statement= Нужно транспонировать не более <tex>\log{n}</tex> поддеревьев.
|proof=Длина пути от вершины до корня может быть и <tex>O(n)</tex>, но нам не нужно подниматься до корня {{---}} достаточно подняться до вершины, у которой свойство левосторонней кучи уже выполнено. Транспонируем только если <tex>dist(x.Lleft) < dist(x.Rright)</tex>, но <tex>dist(x.Rright) \leqslant \log{n}</tex>. На каждом шаге, если нужно транспонируем и увеличиваем <tex>dist</tex>, тогда <tex>dist</tex> увеличится до <tex>\log{n}</tex> и обменов уже не надо будет делать.}}Таким образом, мы восстановили левостороннесть кучи за <tex>O(\log{n})</tex>. Поэтому асимптотика операции <tex> \mathrm{decreaseKey } </tex> {{---}} <tex>O(\log{n})</tex>.
==Построение кучи за O(n)==
После подстановки <tex> x = \genfrac{}{}{}{0}{1}{2} </tex> получаем, что сумма равна <tex> 2 </tex>. Следовательно, построение кучи таким образом произойдёт за <tex> O(n) </tex>.
==Преимущества левосторонней кучи==
Нигде не делается уничтожающих присваиваний. Не создается новых узлов в <tex>\mathrm{merge}</tex>. Эта реализация слияния является функциональной — ее легко реализовать на функциональном языке программирования. Также данная реализация <tex>\mathrm{merge}</tex> является персистентной.
==СсылкиИсточники информации==1. * [http://compscicenter.ru/program/lecture/6829 Лекция "Приоритетные очереди" А. С. Станкевича в Computer Science Center]* [http://www.intuit.ru/studies/courses/100/100/lecture/1539?page=1 Левосторонние кучи. Интуит.]* [[wikipedia:Leftist_tree|Wikipedia {{---}} Leftist tree]]
2. [http://www.intuit.ru/studies/courses/100/100/lecture/1539?page=1 Левосторонние кучи. Интуит.]
 
3. [[wikipedia:Leftist_tree|Wikipedia {{---}} Leftist tree]]
[[Категория: Дискретная математика и алгоритмы]]
[[Категория: Приоритетные очереди]]

Навигация