Персистентная очередь — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Создание страницы)
 
Строка 2: Строка 2:
  
 
== Эффективная реализация ==
 
== Эффективная реализация ==
 +
 +
По сравнению с реализацией на шести стеках, теперь у нас все стеки персистентные, а значит у нас нет необходимости хранить отдельно копию стека <tex>R</tex>, так как все его версии теперь доступны по его персистентности. Это позволяет нам заменить два стека <tex>Rc_1, Rc_2</tex> на один стек <tex>R_2</tex>, в который мы и будем записывать перекопированный кусок.
 +
 +
Персистентная очередь будет состоять из пяти персистентных стеков: <tex>L_1, L_2, R_1, R_2, T</tex>, причем стеки <tex>L_1, L_2</tex> используются для операций <tex>push</tex>, стеки <tex>R_1, R_2</tex> используются для операций <tex>pop</tex>, а стек <tex>T</tex> используется для временного хранения содержимого стека <tex>R</tex>.
 +
 +
В каждый момент времени определено, какой стек <tex>L</tex> из стеков <tex>L_1, L_2</tex> сейчас используется для операций <tex>push</tex>, какой стек <tex>R</tex> из стеков <tex>R_1, R_2</tex> сейчас используется для операций <tex>pop</tex>, а также находится ли очередь в режиме перекопирования (''recopy mode'').
 +
 +
В режиме перекопирования операции <tex>push</tex> перенаправляются в парный стек <tex>L'</tex>; операции <tex>pop</tex> выполняются над последней персистентной версией <tex>R</tex>, тогда операция <tex>empty</tex> всегда возвращает <tex>false</tex>, так как стек <tex>L</tex> содержит <tex>n+1>0</tex> элементов, а в режиме перекопирования мы не можем извлечь их операцией <tex>pop</tex>.
 +
 +
Для хранения последней персистентной версии <tex>R</tex> мы используем второй имеющийся стек <tex>R'</tex>, а также переменную <tex>toCopy</tex> {{---}} количество элементов, оставшихся в <tex>R'</tex>, оно уменьшается на <tex>1</tex> с каждой следующей операцией <tex>pop</tex>.
 +
 +
Режим перекопирования активируется, когда в стеке <tex>L</tex> становится больше элементов, чем в стеке <tex>R</tex>. Пусть в стеке <tex>R</tex> в этот момент находилось <tex>n</tex> элементов, тогда в стеке <tex>L</tex> находилось <tex>n+1</tex> элементов. Заметим, что мы можем корректно обработать только <tex>n</tex> запросов <tex>pop</tex>, операции <tex>push</tex> и <tex>empty</tex> мы обрабатываем корректно всегда, следовательно мы должны закончить перекопирование за <tex>n+1</tex> операцию, включая активирующую.
 +
 +
Для заверешения перекопирования нужно:
 +
# Переместить все содержимое стека <tex>R</tex> в <tex>T</tex>, <tex>n</tex> операций.
 +
# Переместить все содержимое стека <tex>L</tex> в <tex>R</tex>, <tex>n + 1</tex> операция.
 +
# Переместить первые <tex>toCopy</tex> элементов стека <tex>T</tex> в <tex>R</tex>, а оставшиеся элементы выкинуть, <tex>n</tex> операций.
 +
# Обменять местами стеки <tex>L</tex> и <tex>L'</tex>, <tex>2</tex> операции.
 +
 +
Итого, мы должны сделать <tex>3 \cdot n + 3</tex> дополнительных действия за <tex>n + 1</tex> операций, то есть выполняя <tex>O(1)=3</tex> дополнительных действия на операцию, мы сможем завершить перекопирование и вернуться в обычный режим до исчерпания стека <tex>R'</tex>, получив <tex>O(1)</tex> реального времени и <tex>O(1)</tex> памяти на персистентность на операцию.
  
 
[[Категория: Дискретная математика и алгоритмы]]
 
[[Категория: Дискретная математика и алгоритмы]]
 
[[Категория: Амортизационный анализ]]
 
[[Категория: Амортизационный анализ]]

Версия 11:09, 7 июня 2013

После того, как мы получили очередь в реальном времени с [math]O(1)=6[/math] обычными стеками, ее можно легко превратить в персистентную, сделав все стеки персистентными, но реально можно ограничиться всего пятью персистентными стеками.

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

По сравнению с реализацией на шести стеках, теперь у нас все стеки персистентные, а значит у нас нет необходимости хранить отдельно копию стека [math]R[/math], так как все его версии теперь доступны по его персистентности. Это позволяет нам заменить два стека [math]Rc_1, Rc_2[/math] на один стек [math]R_2[/math], в который мы и будем записывать перекопированный кусок.

Персистентная очередь будет состоять из пяти персистентных стеков: [math]L_1, L_2, R_1, R_2, T[/math], причем стеки [math]L_1, L_2[/math] используются для операций [math]push[/math], стеки [math]R_1, R_2[/math] используются для операций [math]pop[/math], а стек [math]T[/math] используется для временного хранения содержимого стека [math]R[/math].

В каждый момент времени определено, какой стек [math]L[/math] из стеков [math]L_1, L_2[/math] сейчас используется для операций [math]push[/math], какой стек [math]R[/math] из стеков [math]R_1, R_2[/math] сейчас используется для операций [math]pop[/math], а также находится ли очередь в режиме перекопирования (recopy mode).

В режиме перекопирования операции [math]push[/math] перенаправляются в парный стек [math]L'[/math]; операции [math]pop[/math] выполняются над последней персистентной версией [math]R[/math], тогда операция [math]empty[/math] всегда возвращает [math]false[/math], так как стек [math]L[/math] содержит [math]n+1\gt 0[/math] элементов, а в режиме перекопирования мы не можем извлечь их операцией [math]pop[/math].

Для хранения последней персистентной версии [math]R[/math] мы используем второй имеющийся стек [math]R'[/math], а также переменную [math]toCopy[/math] — количество элементов, оставшихся в [math]R'[/math], оно уменьшается на [math]1[/math] с каждой следующей операцией [math]pop[/math].

Режим перекопирования активируется, когда в стеке [math]L[/math] становится больше элементов, чем в стеке [math]R[/math]. Пусть в стеке [math]R[/math] в этот момент находилось [math]n[/math] элементов, тогда в стеке [math]L[/math] находилось [math]n+1[/math] элементов. Заметим, что мы можем корректно обработать только [math]n[/math] запросов [math]pop[/math], операции [math]push[/math] и [math]empty[/math] мы обрабатываем корректно всегда, следовательно мы должны закончить перекопирование за [math]n+1[/math] операцию, включая активирующую.

Для заверешения перекопирования нужно:

  1. Переместить все содержимое стека [math]R[/math] в [math]T[/math], [math]n[/math] операций.
  2. Переместить все содержимое стека [math]L[/math] в [math]R[/math], [math]n + 1[/math] операция.
  3. Переместить первые [math]toCopy[/math] элементов стека [math]T[/math] в [math]R[/math], а оставшиеся элементы выкинуть, [math]n[/math] операций.
  4. Обменять местами стеки [math]L[/math] и [math]L'[/math], [math]2[/math] операции.

Итого, мы должны сделать [math]3 \cdot n + 3[/math] дополнительных действия за [math]n + 1[/math] операций, то есть выполняя [math]O(1)=3[/math] дополнительных действия на операцию, мы сможем завершить перекопирование и вернуться в обычный режим до исчерпания стека [math]R'[/math], получив [math]O(1)[/math] реального времени и [math]O(1)[/math] памяти на персистентность на операцию.