Эквивалентность между очередями с приоритетами и сортировкой: различия между версиями

Перейти к навигации Перейти к поиску
Строка 96: Строка 96:




'''Буферы обновления''': базовые сегменты отделяются друг от друга ''базовыми разделителями'', из которых O(log n) выбираются в качестве ''верхних разделителей'', так что количество ключей в базовом списке под i-м верхним разделителем <math>s_i</math> (i > 0) составляет <math>\Theta (4^i(log \; n)^2)</math>. Эти разделители располагаются а атомарной куче. По мере изменений базового списка верхние разделители перемещаются по необходимости с тем, чтобы сохранить их экспоненциальное распределение.
'''Буферы обновления''': базовые сегменты отделяются друг от друга ''базовыми разделителями'', из которых O(log n) выбираются в качестве ''верхних разделителей'', так что количество ключей в базовом списке под i-м (i > 0) верхним разделителем <math>s_i</math> составляет <math>\Theta (4^i(log \; n)^2)</math>. Эти разделители располагаются в атомарной куче. По мере изменений базового списка верхние разделители перемещаются по необходимости с тем, чтобы сохранить их экспоненциальное распределение.




С каждым верхним разделителем <math>s_i</math>, i > 1, ассоциированы три буфера: ''входной буфер'', ''буфер сортировки'' и ''буфер слияния'', каждый емкостью в <math>4^i</math> ключа. Верхний разделитель <math>s_i</math> работает по циклу, состоящему из <math>4^i</math> шагов. В начале цикла входной буфер пуст, буфер сортировки содержит не более <math>4^i</math> обновлений, а буфер слияния – отсортированный список из не более чем <math>4^i</math> обновлений. На каждом этапе можно принять обновление во входной буфер, потратить <math>O(4^i) = S(n)</math> времени на буфер сортировки и O(1) времени на слияние отсортированного списка в буфере слияния, в то время как <math>O(4^i)</math> базовых разделителя находятся в интервале <math>[s_{i - 2}, s_{i + 1})</math> (предполагая <math>s_0 = 0, s_{-1} = - \infty)</math>, и сканирование на наличие нового <math>s_i</math> среди них. Данная реализация гарантирует, что все ключи в буферах разделителя <math>s_i</math> находятся в интервале <math>[s_{i - 2}, s_{i + 1})</math>. Таким образом, после <math>4^i</math> таких шагов цикла отсортированный список корректно слит с базовым списком, найдено новое значение <math>s_i</math> и создан новый отсортированный список. Затем буфер сортировки принимает на себя роль буфера слияния, входной буфер становится буфером сортировки, а пустой буфер слияния становится новым входным буфером.
С каждым верхним разделителем <math>s_i</math>, i > 1, ассоциированы три буфера: ''входной буфер'', ''буфер сортировки'' и ''буфер слияния'', каждый емкостью в <math>4^i</math> ключа. Верхний разделитель <math>s_i</math> работает по циклу, состоящему из <math>4^i</math> шагов. В начале цикла входной буфер пуст, буфер сортировки содержит не более <math>4^i</math> обновлений, а буфер слияния – отсортированный список из не более чем <math>4^i</math> обновлений. На каждом шаге можно принять обновление во входной буфер, потратить <math>O(4^i) = S(n)</math> времени на буфер сортировки и O(1) времени на слияние отсортированного списка в буфере слияния, при этом <math>O(4^i)</math> базовых разделителя находятся в интервале <math>[s_{i - 2}, s_{i + 1})</math> (предполагая <math>s_0 = 0, s_{-1} = - \infty)</math>, и сканирование на наличие нового <math>s_i</math> среди них. Данная реализация гарантирует, что все ключи в буферах разделителя <math>s_i</math> находятся в интервале <math>[s_{i - 2}, s_{i + 1})</math>. Таким образом, после <math>4^i</math> таких шагов цикла отсортированный список корректно слит с базовым списком, найдено новое значение <math>s_i</math> и создан новый отсортированный список. Затем буфер сортировки принимает на себя роль буфера слияния, входной буфер становится буфером сортировки, а пустой буфер слияния становится новым входным буфером.


'''Обработка обновлений''': при получении нового ключа обновления k (вставка или удаление) атомарная куча с верхними разделителями позволяет за время O(1) найти разделитель <math>s_i</math>, такой, что <math>k \in [s_{i - 1}, s_i)</math>. Если <math>k \in [s_0, s_1)</math>, его положение определяется между O(1) базовыми разделителями под s1, и соответствующий базовый сегмент обновляется за время O(1) с использованием атомарной кучи над ключами этого сегмента. Если <math>k \in [s_{i - 1}, s_i)</math> для некоторого i > 1, обновление размещается во входном буфере <math>s_i</math>, выполняя один шаг цикла <math>s_i</math> за время S(n) + O(1). Кроме того, во время каждого обновления выбирается еще один разделитель <math>s_r</math> в порядке круговой очереди, и фрагмент (1/log n) шага цикла <math>s_r</math> выполняется за время O(1). Работа с <math>s_r</math> гарантирует, что после каждых <math>O((log \; n)^2)</math> обновлений выполняется некоторое перемещение каждого верхнего разделителя.


'''Обработка обновлений''': при получении нового ключа обновления k (вставка или удаление) атомарная куча с верхними разделителями позволяет за время O(1) найти разделитель <math>s_i</math>, такой, что <math>k \in [s_{i - 1}, s_i)</math>. Если <math>k \in [s_0, s_1)</math>, определяется его положение среди O(1) базовых разделителей под <math>s_1</math>, и соответствующий базовый сегмент обновляется за время O(1) с использованием атомарной кучи над ключами этого сегмента. Если <math>k \in [s_{i - 1}, s_i)</math> для некоторого i > 1, обновление размещается во входном буфере <math>s_i</math>, выполняя один шаг цикла <math>s_i</math> за время S(n) + O(1). Кроме того, во время каждого обновления выбирается еще один разделитель <math>s_r</math> в порядке круговой очереди, и фрагмент (1/log n) шага цикла <math>s_r</math> выполняется за время O(1). Применение <math>s_r</math> гарантирует, что после каждых <math>O((log \; n)^2)</math> обновлений выполняется некоторое перемещение каждого верхнего разделителя.


Операция find-min возвращает минимальный элемент базового списка, доступный за время O(1).
 
Операция '''find-min''' возвращает минимальный элемент базового списка, доступный за время O(1).