Изменения

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

Персистентная приоритетная очередь

876 байт добавлено, 16:46, 6 февраля 2017
insert
'''Персистентная приоритетная очередь''' (англ. ''persistent priority queue'') {{- это --}} [[Приоритетные очереди|приоритетная очередь]], реализующая [[Персистентные структуры данных|персистентность]], то есть позволяющая получить доступ ко всем своим предыдущим версиям.
== Наивная реализация Реализация с помощью дерева отрезов отрезков ==
=== Идея ===
'''Node''' right
'''T''' key
Node(val : '''T''') <font color="darkgreen">//конструктор для листов</font> Node(leftChild : '''Node''', rightChild : '''Node''') <font color="darkgreen">//конструктор для узлов(присваивает полю key минимальное среди leftChild и rightChild)</font>
</code>
Реализуем следующие функции:
* <tex>\mathrm{build}</tex> {{--- }} построение дерева ,* <tex>\mathrm{insert}</tex> {{--- }} вставка нового элемента очереди,* <tex>\mathrm{extractMin}</tex> {{--- }} удаление минимального элемента очереди,* <tex>\mathrm{merge}</tex> {{--- }} слияние .
Каждая функция возвращает корень нового дерева, которое потом можно будет снова изменять. При реализации можно хранить отдельный массив корней деревьев и при каждом новом изменении какой-либо из версий добавлять измененную в конец массива.
==== insert ====
Вставлять новое значение мы будем в любой пустой лист. Лист считается пустым, если его значение равно <tex>\infty</tex>. При этом не стоит забывать, что те узлы, которые подвергаются изменению, нужно сначала скопировать, а потом вставить новый на основе скопированного для сохранения предыдущих состояний очереди. Запрос вставки нового ключа создает <tex>O(\log n)</tex> новых вершини время его работы <tex>O(n)</tex>.
<code>
'''return''' ''null''
'''else'''
'''return''' Node(currentNode.left, ytemp)
'''else'''
'''return''' Node(ytemp, currentNode.right)</code>
==== extractMin ====
</code>
== Наивная = Недостатки реализации ===У данной реализации есть несколько существенных минусов:#Реализация подразумевает конечный размер очереди, что весьма усложняет использование её в большом диапазоне данных. #Вставка происходит за <tex>O(n)</tex>, что делает данную реализацию бесполезной на большом количестве данных. Такое же время работы можно было получить, если при каждом изменении [[Приоритетные очереди|приоритетной очереди]] просто копировать её и изменять.Более эффективной реализацией является персистентная приоритетная очередь построенная на [[Дерево поиска, наивная реализация |двоичном дереве поиска]]. Все операции, кроме слияния, выполняются за <tex>O(\log n)</tex>. К тому же [[Дерево поиска, наивная реализация|двоичное дерево поиска]] {{---}} динамическая структура, что позволит не думать об ограничении данных из-за реализации. == Реализация с помощью левосторонней кучи ==
Реализуем приоритетную очередь на [[Левосторонняя куча|левосторонней куче]]. Т.к. в [[Левосторонняя куча|левосторонней куче]] нигде не делается уничтожающих присваиваний, то можно её преобразовать в персистентную приоритетную очередь.
dist = min(left.dist, right.dist) + 1
</code>
 
Все предыдущие и текущую версии очереди будем хранить в виде массива корней.
=== Поддерживаемые операции ===
Все операции практически (кроме <tex>\mathrm{merge}</tex>) аналогичны операциям с эфемерной [[Левосторонняя куча|левосторонней кучей]], только каждая из них возвращает корень измененной кучи. В частности <tex>\mathrm{extractMin}</tex> возвращает пару из извлеченной вершины и измененной кучи.
<tex>\mathrm{merge}</tex> примет следующий вид:
<code>
'''LeftistHeap''' merge(x: '''LeftistHeap''', y: '''LeftistHeap'''):
'''if''' x == <tex> \varnothing </tex>:
'''return''' y
'''if''' y == <tex> \varnothing </tex>:
'''return''' x
'''if''' y.key < >= x.key: swap z = LeftistHeap(x.left, merge(x.right, y), x.key) '''else''' z = LeftistHeap(xy.left, '''merge'''(xy.right, yx), xy.key)
'''return''' z
</code>
== Основная идея Реализация с помощью биномиальной кучи ==
Возьмем [[Биномиальная куча|биномиальную кучу]] и реализуем ее на односвязных списках.
Каждый узел в персистентной биномиальной куче представляется набором полей:
* <tex>key</tex> {{---}} ключ (вес) элемента;,* <tex>next</tex> {{---}} указатель на следующий элемент;,* <tex>child</tex> {{---}} указатель на ребенка с большим рангом;,* <tex>degree</tex> {{---}} степень узла (количество дочерних узлов данного узла).
Доступ к куче осуществляется ссылкой на первый корень в списке корней.
Проходим по корневым спискам и создаем новый, объединяя деревья одинакового ранга.
Вспомогательная функция <tex>\mathrm{mergeTree}</tex> объединят в одно деревья одинакового ранга. Для этого мы создаём два новых узла, один из которых {{- --}} новый корень, другой из них {{--- }} видоизмененный корень одного из деревьев.
<code>
'''PersistentBinomialHeap''' mergeTree(t1 : '''PersistentBinomialHeap''', t2 : '''PersistentBinomialHeap'''):
newRoot.degree = t1.degree + t2.degree
'''if''' (t1.key < t2.key)
tmp = PersistentBinomialHeap(t2) <font color = "green">//создаем новый узел путем копирования старого с помощью конструктора</font>
tmp.next = t1.child
newRoot.key = t1.key
==== insert ====
Общий принцип вставки нового элемента схож с принципом вставки в эфемерную обычную [[Биномиальная куча|биномиальную кучу]]. Создаем кучу с деревом ранга <tex>0</tex>, в котором будет единственный элемент {{- --}} тот самый, который нам нужно вставить. И затем сливаем две кучи в одну.
Есть два случая слияния:
а) #Минимальный ранг дерева в куче равен нулю. Тогда сливаем две кучи в одну с помощью <tex>\mathrm{merge}</tex>. Время работы <tex>O(\log n)</tex>. б) #Минимальный ранг дерева в куче отличен от нуля. Тогда присоединяем к созданной куче ту, в которую нужно добавить элемент.ex>. Время работы <tex>O(\log n1)</tex>.
Тогда амортизационная стоимость одной операции <tex>\mathrm{insert}</tex> составляет <tex>O(1)</tex>.
newRoot = PersistentBinomialHeap(newVal)
'''if''' heap.degree == newRoot.degree:
return mergeTreemerge(newRoot, heap)
'''else'''
newRoot.next = heap
</code>
===== Пример работы. Пусть дана куча: [[File:PersistentBinomialHeapExample1_3.png]] Вставим в кучу элемент, с ключом, равным 3. В данном случае выполняется условие под пунктом б). Тогда получим: [[File:PersistentBinomialHeapExample1_4.png]] Теперь вставим в эту же кучу элемент, с ключом, равным 4. Эта ситуация соответствует пункту а). Получим:=====
{| class = "wikitable" width="100%" ! Описание !! Изображение|-align="center"|Исходная куча.|[[File:PersistentBinomialHeapExample1_3.png]]|-align="center"|Вставим в кучу элемент, с ключом, равным <tex>3</tex>. В данном случае выполняется условие под пунктом <tex>2</tex>.|[[File:PersistentBinomialHeapExample1_4.png]]|-align="center"|Теперь вставим в эту же кучу элемент, с ключом, равным <tex>4</tex>. Эта ситуация соответствует пункту <tex>1</tex>. |[[File:PersistentBinomialHeapExample1_5.png]]|}
==== extractMinimum ====
Работает так же как и в эфемерной обычной [[Биномиальная куча|биномиальной куче]]. Проходим по списку корней и находим вершину с минимальным ключом. Затем извлекаем дерево, которое хранит минимальный ключ. Сортируем детей в дереве с минимальным ключом по возрастанию ранга. Сливаем две кучи. <code> '''function''' extractMinimum(t : '''PersistentBinomialHeap'''): tmp = t minimum = t '''while''' tmp != ''null'' '''if''' minimum.key > tmp.key min = tmp tmp = tmp.next; tmp = t H = PersistentBinomialHeap() tmpNewRoot = H '''while''' tmp != ''null'' '''if''' tmp.next == min tmpNewRoot = PersistentBinomialHeap(tmp) tmpNewRoot.next = tmp.next.next '''else''' tmpNewRoot = PersistentBinomialHeap(tmp) tmpNewRoot = tmpNewRoot.next <font color = "green">//расставляем детей в удаленном дереве в возрастающем порядке с помощью вспомогательного массива nodes</font> H' = PersistentBinomialHeap() tmp = min.child x = 0 '''while''' tmp != ''null'' nodes[x] = tmp tmp = tmp.next x = x + 1 tmp = H' '''for''' i = x - 1 '''downto''' 0 tmp.next = PersistentBinomialHeap(nodes[x]) tmp = tmp.next '''return''' (merge(H.next, H'.next), min.key)</code> Функция возвращает минимальный ключ и новую кучу после извлечения минимума. Работает за Время работы операции <tex>O(\log n)</tex>.
== Cм. также ==
*[http://compscicenter.ru/courses/advanced-algo/2013-spring/classes/723/ Лекция А.С. Станкевича по приоритетным очередям]
*[http://logic.pdmi.ras.ru/csclub/node/2734 Лекция П.Ю. Мавривна по персистентным структурам данных]
*[http://ru.wikipedia.org/wiki/Очередь_с_приоритетом_(программирование) Википедия {{- --}} Очередь с приоритетом]
[[Категория: Дискретная математика и алгоритмы]]
[[Категория: Приоритетные очереди]]
[[Категория: Структуры данных‏‎]]
[[Категория: Персистентные структуры данных]]
195
правок

Навигация