Изменения

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

Очередь

397 байт убрано, 21:01, 7 июня 2013
Реализация на шести стеках: правки
Теперь может возникнуть проблема с непустым <tex>Rc</tex> после завершения перекопирования. Покажем, что мы всегда успеем его опустошить, если будем использовать дополнительное извлечение из него при каждой операции в обычном режиме, для этого полностью проанализируем алгоритм.
Пусть на начало перекопирования в стеке <tex>R</tex> содержится <tex>n</tex> элементов, тогда в стеке <tex>L</tex> находится <tex>n+1</tex> элементов. Мы корректно можем обработать любой любое количество операций <tex>push</tex>, а также <tex>n</tex> операций <tex>pop<tex>. Заметим, что операция <tex>empty</tex> во время перекопирования всегда возвращает <tex>false</tex>, так как мы не можем извлекать элементы из стека <tex>L</tex>, который не пустой. Таким образом, вместе с операцией, активирующей перекопирование, мы гарантированно можем корректно обработать <tex>n + 1</tex> операцию.
Посмотрим на дополнительные действия, которые нам предстоят:
# Переместить содержимое <tex>R</tex> в <tex>T</tex>, <tex>n</tex> действий.
# Переместить содержимое <tex>L</tex> в стеки <tex>R, Rc'</tex>, <tex>n + 1</tex> действий.
# Переместить первые <tex>toCopy</tex> элементов из <tex>T</tex> в <tex>R, Rc'</tex>, <tex>n</tex> действий.
# Поменять ролями стеки <tex>Rc, Rc'</tex>, <tex>L, L'</tex>, <tex>2</tex> действийдействия.
Таким образом, получили <tex>3 \cdot n + 3</tex> дополнительных действия за <tex>n + 1</tex> операций, или <tex>3=O(1)</tex> дополнительных действия на операцию в режиме перекопирования, что и требовалось.
Теперь рассмотрим, как изменились наши стеки за весь период перекопирования. Договоримся, что операция <tex>empty</tex> не меняет очередь, то есть никакие дополнительные действия не совершаются. Пусть за <tex>n</tex> следующих за активацией меняющих операций (<tex>push, pop</tex>) поступило <tex>x</tex> операций <tex>pop</tex>, <tex>n - x</tex> операций <tex>push</tex>. Очевидно, что после перекопирования в новых стеках окажется: в <tex>L</tex> <tex>n-x</tex>, элементов в <tex>RL</tex> , <tex>2 \ cdot n + 1 - x = (n - x) + (n + 1)</tex> элементов в <tex>R</tex>, то есть до следующего перекопирования еще <tex>n+2</tex> операции. С другой стороны, стек <tex>Rc</tex> содержал всего <tex>n</tex> элементов, так что мы можем почистить ихочистить его, просто удаляя по одному элементу при каждой операции в обычном режиме.
Итак, очередь <tex>Q</tex> будет состоять из шести стеков <tex>L,L',R,Rc,Rc',T</tex>, а также двух внутренних переменных <tex>recopy, toCopy</tex>, которые нужны для корректности перекопирования.
Инвариант нашей очереди (обычный режим):
# <tex>L.size \leqslant R.size</tex>
# <tex>R.size = 0 \equiv Q.size = 0</tex>
# <tex>Rc</tex> {{---}} копия <tex>R</tex>
# <tex>Rc'.size < R.size - L.size</tex># <tex>L'.size = 0, T.size = 0</tex>
Очередь будет работать в двух режимах:# Обычный режим, кладем в Тогда к следующему перекопированию (<tex>L</tex>, извлекаем из <tex>.size=R.size+1</tex> и из ) мы гарантированно будем иметь пустые стеки <tex>L',T,Rc'</tex> для поддержания порядка, которые нам понадобятся.#
Инвариант очереди (режим перекопирования):
# <tex>Rc.size = toCopy</tex>
# Если <tex>L.size = 0</tex>, то первые <tex>toCopy</tex> элементов <tex>T</tex> {{---}} корректны, то есть действительно содержатся в очереди.
Таким образомОчередь будет работать в двух режимах:# Обычный режим, кладем в <tex>L</tex>, получили извлекаем из <tex>3 \cdot n + 3R</tex> действий на и из <tex>n + 1Rc, Rc'</tex> операций с очередьюдля поддержания порядка, то есть выполняя 3 дополнительных действия во время операции мы успеем перекопировать все элементы вовремя. Тогда очередь действительно будет выполнять каждое действие за операция <tex>Oempty = (1R.size = 0)<tex>.# Режим перекопирования, кладем в <tex>L'</tex>, извлекаем из <tex>Rc</tex>, <tex>empty=false</tex> реального времени, совершаем дополнительные действия.
Теперь рассмотрим, какие изменения произошли за время Также после операции в обычном режиме следует проверка на активацию перекопирования. Пусть среди (<tex>n</tex> следующих за активацией операций у нас <tex>x</tex> операций <tex>pop</tex> и <tex>n-x</tex> операций <tex>push</tex>recopy = (L. Тогда в стеке <texsize >R</tex> оказалось <tex>2 \cdot n + 1 - x</tex> элементов, а в новом стеке <tex>L</tex> оказалось <tex>n - x</tex> элементов. Тогда в стеке <tex>R</tex> на <tex>n+1size)</tex> больше элементов), чем в стеке <tex>L</tex>, а если это значиттак, что до следующего режима перекопирования <tex>n + 2</tex> операции, и за это время мы успеем очистить старый стек <tex>Rc</tex>, в котором находится максимум <tex>n</tex> ненужных элементовtoCopy=R.size, просто удаляя при каждой операции в обычном режиме один элемент из <tex>Rcrecopy=true</tex>, если он непустсовершается первый набор дополнительных действий.
Заметим, что вышеприведенный алгоритм гарантирует нам, что После операции в обычном режиме в стеке перекопирования следует проверка на завершение перекопирования (<tex>Lrecopy=T.size==0</tex> находится не больше элементов), чем в а при завершении меняются ролями стеки <tex>RRc, Rc'</tex>, так что проверка на пустоту очереди при обычном режиме сводится к проверке на пустоту стека <tex>RL, L'</tex>.
Пусть наша очередь <tex>Q</tex> имеет стеки <tex>L1L, L2L', R, Rc1Rc, Rc2Rc', T</tex>, а также переменные <tex>recopy</tex> и <tex>toCopy</tex>, тогда следующий псевдокод выполняет требуемые операции.
=== empty ===
<code>
push(x)
if !recopy
L1L.push(x) if Rc'.size > 0 Rc'.pop()
checkRecopy()
else
L2L'.push(x)
checkNormal()
</code>
if !recopy
tmp = R.pop()
Rc1Rc.pop() if Rc'.size > 0 Rc'.pop()
checkRecopy()
return tmp
else
tmp = Rc1Rc.pop()
toCopy = toCopy - 1
checkNormal()
=== checkRecopy ===
<code>
checkRecopy() if Rc2.size > 0 Rc2.pop() recopy = L1L.size > R.size
if recopy
toCopy = Rc1R.size
additionalOperations()
</code>
T.push(R.pop())
toDo = toDo - 1
// Пытаемся перекопировать L1 L в R и Rc2Rc'
while toDo > 0 and L1.size > 0
x = L1L.pop()
R.push(x)
Rc2Rc'.push(x)
toDo = toDo - 1
// Пытаемся перекопировать T в R и Rc2 Rc' с учетом toCopy
while toDo > 0 and T.size > 0
x = T.pop()
if toCopy > 0
R.push(x)
Rc2Rc'.push(x)
toCopy = toCopy - 1
toDo = toDo - 1
// Если все скопировано, то меняем роли L1, L2 и Rc1, Rc2
if T.size = 0
swap(L1L, L2L') swap(Rc1Rc, Rc2Rc')
</code>
120
правок

Навигация