Изменения

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

Персистентный стек

1414 байт добавлено, 23:29, 5 сентября 2019
м
Правка орфографии
''Персистентными структурами данных'' называются структуры, хранящие все свои промежуточные версии.== Алгоритм ==
=== Реализация на массиве ===
Заведем массив запросов, модифицирующих стек.<br>
'''struct''' '''Query''':
'''T''' value
'''uint''' prev
У каждого элемента массива будет <tex>2</tex> поля: значение в вершине стека и индекс предыдущей версии стека.<br>
Тогда операции push и pop будут иметь следующий вид:<br>
* <tex> \mathrm{push}(i, x)</tex> {{---}} добавляет элемент <tex>x</tex> в стек с номером <tex>i</tex>, результирующий стек будет иметь номер <tex> n + 1 </tex>,
'''function''' push(i : '''uint''', x : '''T'''):
s.top = s.top + 1
s[s.top].value = x
s[s.top].prev = i
* <tex>\mathrm{pop}(i)</tex> {{---}} возвращает значение, хранящееся в элементе с номером <tex>i</tex> и копирует элемент, предыдущий для него, результирующий стек будет иметь номер <tex> n + 1 </tex>.
'''T''' pop(i : '''uint'''):
'''Query''' k = s[i]
k = s[k.prev]
push(k.prev, k.value)
'''return''' s[i].value
Рассмотрим такую структуру === Реализация на списке ===Будем использовать узел, у которого будет значение и ссылка на примере [[стек|прошлую версию стека. При этом сам узел - это версия стека]]. '''struct''' '''Node''': '''T''' value== Наивная реализация == '''Node''' prevСамое простое и очевидное решение этой задачи — честное копирование стека при каждой операцииБудем хранить состояния в узлах. Будем возвращать пользователю информацию о текущей вершине. <br>Очевидно, это не самое эффективное решение. Сложность одной операции составляет У каждого узла будет <tex>O(n)2</tex> поля: значение в вершине стека и количество требуемой памяти — ссылка на предыдущую версию стека.<br>Сам персистентный стек будет обозначаться <tex>O(n^2)s</tex>.<br>
* <tex> \mathrm{push}(i, x)</tex> {{---}} добавляет элемент <tex>x</tex> в стек узла <tex>i</tex>, '''Stack''' push(i : '''Node''', x : '''T'''): k.value =x k.prev = Эффективная реализация =i s.top =k '''return''' s
Попробуем решить задачу эффективнее. Заведем массив запросов, модифицирующих стек.<br>У каждого элемента массива будет 2 поля: значение в вершине стека и индекс предыдущей версии стека.<br>Тогда операции push и pop будут иметь следующий вид:<br>* <tex>push\mathrm{pop}(i, x)</tex> — добавляет элемент х {{---}} возвращает значение, хранящееся в стек с номером i, результирующий стек будет иметь номер <tex> n + 1 </tex>. mas.push_back(value = x, prev = i)* узле <tex>pop(i)</tex> — возвращает значение, хранящееся в элементе с номером i и копирует элемент, предыдущий для него.результирующий стек будет иметь номер '''pair<tex> n + 1 </texT, Stack>''' pop(i : '''Node'''): '''T''' val = i.value mas.push_back( copy_of(mas[ i = i.prev]) '''return''' pair(val, s)
== Пример ==
* Пусть изначально у нас есть один пустой стек. Запишем его в массив.
[[Файл:стек1.png|500px|nothumb|right|]]
{| border = 1; cellspacing = 0; class="wikitable"
|-align = "center"
!value
|<tex>\mathtt{null}</tex>
|-align = "center"
!prev
|<tex>\mathtt{null}</tex>
|}
* Далее выполним <tex>\mathrm{push}(1, 3)</tex>. Создается новая вершина со значением <tex>3</tex>, ссылающаяся на 1-ую, помещаем ее во 2-ую ячейку массива:
[[Файл:стек2.png|500px|nothumb|right|]]
{| border = 1; cellspacing = 0; class="wikitable"
|-align = "center"
!value
|<tex>\mathtt{null}</tex>
|3
|-align = "center"
!prev
|<tex>\mathtt{null}</tex>
|1
|}
* Аналогично выполним <tex>\mathrm{push}(2, 5)</tex>:
[[Файл:стек3.png|500px|nothumb|right|]]
{| border = 1; cellspacing = 0; class="wikitable"
|-align = "center"
!value
|<tex>\mathtt{null}</tex>
|3
|5
|-align = "center"
!prev
|<tex>\mathtt{null}</tex>
|1
|2
* Выполним <tex>\mathrm{pop}(3)</tex>. он Он возвращает <tex>5 </tex> и копирует 2-ую вершину.
[[Файл:стек4.png|500px|nothumb|right|]]
{| border = 1; cellspacing = 0; class="wikitable"
|-align = "center"
!value
|<tex>\mathtt{null}</tex>
|3
|5
|-align = "center"
!prev
|<tex>\mathtt{null}</tex>
|1
|2
* Так будет выглядеть массив после последовательности операций <tex>\mathrm{push}(3, 6), \mathrm{push}(5, 1), \mathrm{pop}(4), \mathrm{pop}(5), \mathrm{push}(7, 9):</tex>
[[Файл:стек.png|500px|nothumb|right|]]
{| border = 1; cellspacing = 0; class="wikitable"
|-align = "center"
!value
|<tex>\mathtt{null}</tex>
|3
|5
|6
|1
|<tex>\mathtt{null}</tex>
|5
|9
|-align = "center"
!prev
|<tex>\mathtt{null}</tex>
|1
|2
|3
|5
|<tex>\mathtt{null}</tex>
|2
|7
В итоге мы имеем доступ ко всем версиям стека за <tex>O(1)</tex> времени и <tex>O(n)</tex> памяти.
== Применение ==Используя персистентый стек, можно реализовать легко перстистентную очередь (если вспомнить её реализацию на двух стеках). <br>См. [[Персистентная очередь]]
== См. также==
* [[Персистентный дек]]
== Ссылки Источники информации ==
* [http://habrahabr.ru/blogs/algorithm/113585/ Habrahabr {{---}} Персистентный стек - статья на хабре]
[[Категория:Дискретная математика и алгоритмы]]
[[Категория: Амортизационный анализ]]
[[Категория: Структуры данных]]
24
правки

Навигация