Персистентный стек — различия между версиями
Yurik (обсуждение | вклад) |
Yurik (обсуждение | вклад) |
||
| Строка 9: | Строка 9: | ||
Самое простое и очевидное решение этой задачи — честное копирование стека при каждой операции. <br> | Самое простое и очевидное решение этой задачи — честное копирование стека при каждой операции. <br> | ||
| − | Очевидно, | + | Очевидно, это не самое эффективное решение. Сложность одной операции составляет <tex>O(n)</tex> и количество требуемой памяти — <tex>O(n^2)</tex>. |
== Эффективная реализация == | == Эффективная реализация == | ||
| − | + | Попробуем решить задачу эффективнее. Заведем массив запросов, модифицирующих стек.<br> | |
| − | Попробуем решить задачу эффективнее. Заведем массив запросов, модифицирующих стек. | + | У каждого элемента массива будет 2 поля: значение в вершине стека и индекс предыдущей версии стека.<br> |
| − | |||
| − | У каждого элемента массива будет 2 поля: значение в вершине стека и индекс предыдущей версии стека. | ||
| − | |||
Тогда операции push и pop будут иметь следующий вид:<br> | Тогда операции push и pop будут иметь следующий вид:<br> | ||
| − | * <tex>push(i, x)</tex> — добавляет элемент х | + | * <tex>push(i, x)</tex> — добавляет элемент х в стек с номером i, результирующий стек будет иметь номер <tex> n + 1 </tex>. |
* <tex>pop(i)</tex> — возвращает значение, хранящееся в элементе с номером i и копирует элемент, предыдущий для него. | * <tex>pop(i)</tex> — возвращает значение, хранящееся в элементе с номером i и копирует элемент, предыдущий для него. | ||
| − | результирующий стек будет иметь номер n + 1. | + | результирующий стек будет иметь номер <tex> n + 1 </tex>. |
== Пример == | == Пример == | ||
| − | Пусть изначально у нас есть один пустой стек. Запишем его в массив. | + | * Пусть изначально у нас есть один пустой стек. Запишем его в массив. |
| − | |||
{| border = 1; cellspacing = 0; class="wikitable" | {| border = 1; cellspacing = 0; class="wikitable" | ||
|- align = "center" | |- align = "center" | ||
!index | !index | ||
| − | + | !1 | |
|-align = "center" | |-align = "center" | ||
!value | !value | ||
| Строка 40: | Строка 36: | ||
|} | |} | ||
| − | + | ||
| − | + | * Далее выполним <tex>push(1, 3)</tex>. Создается новая вершина со значением 3, ссылающаяся на 1-ую, помещаем ее во 2-ую ячейку массива: | |
| − | Далее выполним <tex>push(1, 3)</tex>. Создается новая вершина со значением 3, ссылающаяся на 1-ую, помещаем ее во | ||
| − | |||
{| border = 1; cellspacing = 0; class="wikitable" | {| border = 1; cellspacing = 0; class="wikitable" | ||
|- align = "center" | |- align = "center" | ||
!index | !index | ||
| − | + | !1 | |
| − | + | ! 2 | |
|-align = "center" | |-align = "center" | ||
!value | !value | ||
| Строка 59: | Строка 53: | ||
|} | |} | ||
| − | + | ||
| − | Аналогично выполним <tex>push(2, 5)</tex>: | + | * Аналогично выполним <tex>push(2, 5)</tex>: |
| − | |||
{| border = 1; cellspacing = 0; class="wikitable" | {| border = 1; cellspacing = 0; class="wikitable" | ||
|- align = "center" | |- align = "center" | ||
!index | !index | ||
| − | + | !1 | |
| − | + | ! 2 | |
| − | + | ! 3 | |
|-align = "center" | |-align = "center" | ||
!value | !value | ||
| Строка 80: | Строка 73: | ||
|} | |} | ||
| − | |||
| − | |||
| − | + | * Выполним <tex>pop(3)</tex>. он возвращает 5 и копирует 2-ую вершину. | |
| − | * Выполним <tex>pop(3)</tex>. он возвращает 5 и копирует | ||
| − | |||
{| border = 1; cellspacing = 0; class="wikitable" | {| border = 1; cellspacing = 0; class="wikitable" | ||
|- align = "center" | |- align = "center" | ||
!index | !index | ||
| − | + | !1 | |
| − | + | ! 2 | |
| − | + | ! 3 | |
| − | + | ! 4 | |
|-align = "center" | |-align = "center" | ||
!value | !value | ||
| Строка 107: | Строка 96: | ||
|} | |} | ||
| − | |||
| − | Так будет выглядеть массив после последовательности операций <tex>push(3, 6), push(5, 1), pop(4), pop(5), push(7, 9):</tex> | + | * Так будет выглядеть массив после последовательности операций <tex>push(3, 6), push(5, 1), pop(4), pop(5), push(7, 9):</tex> |
{| border = 1; cellspacing = 0; class="wikitable" | {| border = 1; cellspacing = 0; class="wikitable" | ||
|- align = "center" | |- align = "center" | ||
!index | !index | ||
| − | + | !1 | |
| − | + | ! 2 | |
| − | + | ! 3 | |
| − | + | ! 4 | |
| − | + | ! 5 | |
| − | + | ! 6 | |
| − | + | ! 7 | |
| − | + | ! 8 | |
| − | + | ! 9 | |
|-align = "center" | |-align = "center" | ||
!value | !value | ||
| Строка 148: | Строка 136: | ||
<br> | <br> | ||
| − | В итоге мы имеем доступ ко всем версиям стека за <tex>O(1)</tex> времени и <tex>O(n)</tex> памяти | + | В итоге мы имеем доступ ко всем версиям стека за <tex>O(1)</tex> времени и <tex>O(n)</tex> памяти. |
== См. также== | == См. также== | ||
Версия 16:34, 7 июня 2012
| Определение: |
| Персистентными структурами данных называются такие структуры, хранящие все свои промежуточные версии. |
Рассмотрим такую структуру на примере стека.
Наивная реализация
Самое простое и очевидное решение этой задачи — честное копирование стека при каждой операции.
Очевидно, это не самое эффективное решение. Сложность одной операции составляет и количество требуемой памяти — .
Эффективная реализация
Попробуем решить задачу эффективнее. Заведем массив запросов, модифицирующих стек.
У каждого элемента массива будет 2 поля: значение в вершине стека и индекс предыдущей версии стека.
Тогда операции push и pop будут иметь следующий вид:
- — добавляет элемент х в стек с номером i, результирующий стек будет иметь номер .
- — возвращает значение, хранящееся в элементе с номером i и копирует элемент, предыдущий для него.
результирующий стек будет иметь номер .
Пример
- Пусть изначально у нас есть один пустой стек. Запишем его в массив.
| index | 1 |
|---|---|
| value | |
| prev |
- Далее выполним . Создается новая вершина со значением 3, ссылающаяся на 1-ую, помещаем ее во 2-ую ячейку массива:
| index | 1 | 2 |
|---|---|---|
| value | 3 | |
| prev | 1 |
- Аналогично выполним :
| index | 1 | 2 | 3 |
|---|---|---|---|
| value | 3 | 5 | |
| prev | 1 | 2 |
- Выполним . он возвращает 5 и копирует 2-ую вершину.
| index | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| value | 3 | 5 | 3 | |
| prev | 1 | 2 | 1 |
- Так будет выглядеть массив после последовательности операций
| index | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|
| value | 3 | 5 | 3 | 6 | 1 | 5 | 9 | ||
| prev | 1 | 2 | 1 | 3 | 5 | 2 | 7 |
В итоге мы имеем доступ ко всем версиям стека за времени и памяти.