Персистентный стек — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 19: Строка 19:
  
 
Тогда операции push и pop будут иметь следующий вид:<br>
 
Тогда операции push и pop будут иметь следующий вид:<br>
* <tex>push(x, i)</tex> — добавляет элемент х к стеку с номером i, результирующий стек будет иметь номер n + 1.
+
* <tex>push(i, x)</tex> — добавляет элемент х к стеку с номером i, результирующий стек будет иметь номер n + 1.
 
* <tex>pop(i)</tex> — возвращает значение, хранящееся в элементе с номером i и копирует элемент, предыдущий для него.
 
* <tex>pop(i)</tex> — возвращает значение, хранящееся в элементе с номером i и копирует элемент, предыдущий для него.
 
 
результирующий стек будет иметь номер n + 1.
 
результирующий стек будет иметь номер n + 1.
 
  
  
 
== Пример ==
 
== Пример ==
  
Пусть изначально у нас есть один пустой стек. Для удобства, будем хранить его как «голову» с пометкой пустого стека:
+
Пусть изначально у нас есть один пустой стек. Запишем его в массив.
 
<br>
 
<br>
[[Файл:B5bb212f3702e565498c4412e13242a7.jpg|Картинка]]<br>
+
{| border = 1; cellspacing = 0; class="wikitable"
 +
|- align = "center"
 +
!index
 +
|1
 +
|-align = "center"
 +
!value
 +
|<tex>null</tex>
 +
|-align = "center"
 +
!prev
 +
|<tex>null</tex>
 +
|}
 +
 
 
<br>
 
<br>
 
<br>
 
<br>
Далее выполним <tex>push(1, 5)</tex>. Создается новая вершина со значением 5, ссылающаяся на 1-ую:
+
Далее выполним <tex>push(1, 3)</tex>. Создается новая вершина со значением 3, ссылающаяся на 1-ую, помещаем ее во 2ю ячейку массива:
 
<br>
 
<br>
[[Файл:612b6fe1562242b3a455b2abb698dfc9.jpg|nothumb]]<br>
+
{| border = 1; cellspacing = 0; class="wikitable"
 +
|- align = "center"
 +
!index
 +
|1
 +
|&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;
 +
|-align = "center"
 +
!value
 +
|<tex>null</tex>
 +
|3
 +
|-align = "center"
 +
!prev
 +
|<tex>null</tex>
 +
|1
 +
|}
 +
 
 
<br>
 
<br>
Аналогично выполним <tex>push(2, 10)</tex> и <tex>push(1, 6)</tex>:
+
Аналогично выполним <tex>push(2, 5)</tex>:
<br><br>
 
[[Файл:2beb71892fd79b675e095d5432827d03.jpg|nothumb]]
 
 
<br>
 
<br>
 +
{| border = 1; cellspacing = 0; class="wikitable"
 +
|- align = "center"
 +
!index
 +
|1
 +
|&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;
 +
|-align = "center"
 +
!value
 +
|<tex>null</tex>
 +
|3
 +
|5
 +
|-align = "center"
 +
!prev
 +
|<tex>null</tex>
 +
|1
 +
|2
 +
|}
  
Очевидно, что все 4 стека сейчас верно построены и легко восстанавливаются. Давайте теперь попробуем выполнить последовательно операции <tex>pop(2)</tex> и <tex>pop(3)</tex>:
+
<br>
 +
<br>
  
 
<br>
 
<br>
* <tex>pop(2)</tex> возвращает 5 и копирует 1-ую вершину. Результирующий пятый стек — пустой.
+
* Выполним <tex>pop(3)</tex>. он возвращает 5 и копирует вершину.
 
<br>
 
<br>
[[Файл:3ab7456751529d76c5f1392d5d3b5fcb.jpg|nothumb]]
+
{| border = 1; cellspacing = 0; class="wikitable"
 +
|- align = "center"
 +
!index
 +
|1
 +
|&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;
 +
|-align = "center"
 +
!value
 +
|<tex>null</tex>
 +
|3
 +
|5
 +
|3
 +
|-align = "center"
 +
!prev
 +
|<tex>null</tex>
 +
|1
 +
|2
 +
|1
 +
|}
  
 
<br><br>
 
<br><br>
  
* <tex>pop(3)</tex> возвращает 10 и копирует 2-ую вершину: получаем шестой стек.
+
Так будет выглядеть массив после последовательности операций <tex>push(3, 6), push(5, 1), pop(4), pop(5), push(7, 9):</tex>
<br><br>
+
 
[[Файл:Eced2ebbcee643d6c87576b0d3460785.jpg|nothumb]]<br>
+
{| border = 1; cellspacing = 0; class="wikitable"
 +
|- align = "center"
 +
!index
 +
|1
 +
|&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;
 +
|&nbsp;&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;
 +
|-align = "center"
 +
!value
 +
|<tex>null</tex>
 +
|3
 +
|5
 +
|3
 +
|6
 +
|1
 +
|<tex>null</tex>
 +
|5
 +
|9
 +
|-align = "center"
 +
!prev
 +
|<tex>null</tex>
 +
|1
 +
|2
 +
|1
 +
|3
 +
|5
 +
|<tex>null</tex>
 +
|2
 +
|7
 +
|}
 
<br>
 
<br>
  

Версия 16:20, 7 июня 2012

Определение:
Персистентными структурами данных называются такие структуры, хранящие все свои промежуточные версии.


Рассмотрим такую структуру на примере стека.


Наивная реализация

Самое простое и очевидное решение этой задачи — честное копирование стека при каждой операции.
Очевидно, что это не самое эффективное решение. Сложность одной операции составляет [math]O(n)[/math] и количество требуемой памяти — [math]O(n^2)[/math].

Эффективная реализация

Попробуем решить задачу эффективнее. Заведем массив запросов, модифицирующих стек.

У каждого элемента массива будет 2 поля: значение в вершине стека и индекс предыдущей версии стека.

Тогда операции push и pop будут иметь следующий вид:

  • [math]push(i, x)[/math] — добавляет элемент х к стеку с номером i, результирующий стек будет иметь номер n + 1.
  • [math]pop(i)[/math] — возвращает значение, хранящееся в элементе с номером i и копирует элемент, предыдущий для него.

результирующий стек будет иметь номер n + 1.


Пример

Пусть изначально у нас есть один пустой стек. Запишем его в массив.

index 1
value [math]null[/math]
prev [math]null[/math]



Далее выполним [math]push(1, 3)[/math]. Создается новая вершина со значением 3, ссылающаяся на 1-ую, помещаем ее во 2ю ячейку массива:

index 1     2    
value [math]null[/math] 3
prev [math]null[/math] 1


Аналогично выполним [math]push(2, 5)[/math]:

index 1     2         3    
value [math]null[/math] 3 5
prev [math]null[/math] 1 2




  • Выполним [math]pop(3)[/math]. он возвращает 5 и копирует 2ю вершину.


index 1     2         3         4    
value [math]null[/math] 3 5 3
prev [math]null[/math] 1 2 1



Так будет выглядеть массив после последовательности операций [math]push(3, 6), push(5, 1), pop(4), pop(5), push(7, 9):[/math]

index 1     2         3         4         5         6         7         8         9    
value [math]null[/math] 3 5 3 6 1 [math]null[/math] 5 9
prev [math]null[/math] 1 2 1 3 5 [math]null[/math] 2 7


В итоге мы имеем доступ ко всем версиям стека за [math]O(1)[/math] времени и [math]O(n)[/math] памяти (массив длины n и n самих "стеков").

См. также

Ссылки