Изменения

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

List order maintenance

494 байта добавлено, 23:56, 10 апреля 2016
Structure
[[Файл:ListABCD.jpg|250px|thumb|right|Для такого списка команда <tex>\mathrm{order(D,B)}</tex> выдаст <tex>\mathrm{false}</tex>.]]
'''List order maintance''' (русскрус. <i>поддержка порядка в списке</i>) {{---}} проблема поддержки списка со следующими операциями:
* <tex>\mathrm{insert(p, q)}</tex> {{---}} вставка нового элемента <tex>p</tex> в список сразу после <tex>q</tex>;
* <tex>\mathrm{remove(p)}</tex> {{---}} удаление элемента <tex>p</tex> из списка;
Существует реализация структуры, где все операции выполняются за амортизационную <tex>O(1)</tex>.
Список Потребность в списке с командой порядка используется в разных алгоритмах и структурахвозникает, к примеру, в реализации полностью [[Персистентные структуры данных|персистентного дерева поиска]].
== Алгоритм за O(logn) ===== Идея ===
[[Файл:ListABCDwithMarks.jpg|250px|thumb|right|Пример расставления меток для списка, <tex>u=3</tex>.]]
Рассмотрим реализацию списка с командой порядкаВсе операции кроме <tex>\mathrm{order(p, где все операции выполняются q)}</tex> за амортизационную <tex>O(\log n1)</tex>может выполнить обычный [[Список|двусвязный список]]. Дадим Проблема возникает в тот момент, когда мы хотим получить порядок элементов, так как связный список не хранит информацию о нём. Пусть каждому элементу узлу сопоставлено некоторое число, при этом все числа строго возрастают от начала списка к его концу. Таким образом, эти числа, которые в дальнейшим будут называться метками, задают порядок на элементах списка метки длины . И, зная ссылки на два элемента <tex>p</tex> и <tex>q</tex>, можно за <tex>uO(1)</tex> из битов. Пусть ответить на запрос <tex>u:\dfracmathrm{norder(p,q)}</tex>, просто сравнив их метки. Заметим, что добавление меток никак не влияет на реализацию операции <tex>\mathrm{2remove(p)}<2^u /tex>. Однако с реализацией <tex>\leqslant 2nmathrm{insert(p,q)}</tex>, где возникают проблемы: при добавлении нового элемента <tex>nq</tex> {{---}} количество элементов в списке. Если после добавления или удаления элементов узла <tex>up</tex> перестанет удовлетворять неравенству, пересчитаем все метки заново. Пересчет меток занимает амортизационно узлу <tex>O(1)q</tex> по аналогии с саморасширяющимся массивомнадо присвоить метку, которая строго больше предыдущего элемента и строго меньше следующего. Пусть Исходя из предположения, что метки имеют конечную длину, в какой-то момент возникнет ситуация, что новой метки идут по возрастанию от начала к концу не найдётся. Тогда будем выдавать элементам спискановые метки. Теперь рассмотрим алгоритм, который позволяет реализовать эту идею. Опишем взаимодействие с метками при выполнении операций:
* <b>операция порядка:</b> <tex>\mathrm{order(p,q)}</tex> можно сделать, просто сравнив метки === Алгоритм за <tex>O(1logn)</tex> (так как они идут по возрастанию);===* <b>удаление вершины:</b> для выполнения <tex>\mathrm{remove(p)}</tex> просто удалим элемент <tex>p</tex> вместе с его меткой за <tex>O(1)</tex> Метки будем хранить в виде чисел в двоичной системе счисления. Посмотрим, проверимкакой длины должны быть метки, удовлетворяет ли чтобы перераспределения не случались слишком часто. Если <tex>u</tex> неравенству, если нет {{---}} пересчитаем;* <b>добавление вершины:</b> длина каждой метки, то для начала пусть <tex>u:\mathrmdfrac{n}{insert(p,q)2}<2^u \leqslant 2n</tex> существуют два возможных случая:** <b>есть свободная метка:</b> проверим, есть ли между элементом где <tex>rn</tex> и следующим за ним элементом свободная метка{{---}} количество элементов в списке. Если есть, дадим после добавления или удаления элементов <tex>qu</tex> любую свободную метку между нимиперестанет удовлетворять неравенству, пересчитаем все метки заново. После этого опять проверим Пересчет меток занимает амортизационно <tex>uO(1)</tex> на соответствие неравенствупо аналогии с саморасширяющимся массивом. [[Файл:UBitTreeListABCD.jpg|350px|thumb|right|Точка {{---}} метка Позже, в листе используется.]]** <b>свободной метки нет:</b> В случаедоказательстве времени работы, если между мы несколько уточним значение <tex>pu</tex> и следующим за ним элементом свободной метки нет, нам придется пересчитать метки описанным ниже способом.
 <b>Способ хранения меток.</b> Все Будем хранить все метки хранятся в [[Сверхбыстрый цифровой бор | цифровом боре]] высоты <tex>u</tex> (там хранятся не только используемые метки, а вообще все возможные заданной длины). В узлах будем хранить:* <b>в листьях</b> будем хранить, используется ли уже эта метка. Пусть <tex>\mathrm{weight(x)}</tex> {{---}} это количество помеченных (используемых) листьев (меток) в поддереве <tex>x</tex>, а <tex>\mathrm{size(x)}</tex> {{---}} это количество всех листьев в поддереве <tex>x</tex>;[[Файл:UBitTreeExample.jpg|350px|thumb|right|Пример цифрового бора для меток, где узел с крестиком {{---}} переполненный узел, а с галочкой {{---}} непереполненный для <tex>\alpha=1,5</tex>.]]
* <b>в нелистовых узлах</b> будем хранить, является ли узел переполненным. Для любой <tex>1<\alpha<2</tex> будем считать, что узел дерева переполнен, если <tex>\dfrac{\mathrm{weight(x)}}{\mathrm{size(x)}}>\dfrac{1}{\alpha^{\mathrm{height(x)}}}</tex>. Стоит заметить, что все листья всегда непереполнены. В худшем случае: <tex> \dfrac{\mathrm{weight(leave)}}{\mathrm{size(leave)}} = 1 = \dfrac{1}{\alpha^{\mathrm{height(x)}}} = \dfrac{1}{\alpha^{0}}</tex>. Получается, что, чем выше, тем более разреженными должны быть поддеревья непереполненных узлов.
[[Файл:UBitTreeExample.jpg|350px|thumb|right|Пример цифрового бора для меток, где узел с крестиком {{---}} переполненный узел, а с галочкой {{---}} непереполненный для <tex>\alpha=1,5</tex>.]]
<b>Перераспределение меток.</b> Тогда, как только мы получаем команду вставить элемент, которому не хватает метки, мы поднимаемся вверх от метки элемента <tex>p</tex>, пока не найдем первый непереполненный узел. Может случиться такое, что на всем пути до корня мы не найдем ни одного непереполненного узла. Чтобы этого избежать, изменим требования к <tex>u</tex> позже. Как только мы нашли первый непереполненный узел, переназначим метки в его поддереве так, чтобы они находились друг от друга на одинаковых расстояниях (места точно хватит, так как <tex>\dfrac{\mathrm{weight(x)}}{\mathrm{size(x)}}\leqslant\dfrac{1}{\alpha^{\mathrm{height(x)}}}</tex>, если узел непереполненный). После этого плотность распределения всех занятых листьев составит примерно <tex>\dfrac{1}{\alpha^{\mathrm{height(x)}}}</tex>.
 
<b>Докажем амортизационную стоимость операции добавления.</b>
Теперь выберем такое <tex>u</tex>, чтобы корень никогда не переполнялся: <tex>\dfrac{\mathrm{weight(root)}}{\mathrm{size(root)}} < \dfrac{1}{\alpha^{\mathrm{height(root)}}} \Rightarrow \dfrac{n}{2^u} < \dfrac{1}{\alpha ^u} \Rightarrow u \geqslant \log_{\frac{ 2}{\alpha}} n</tex>. Тогда операция добавления работает за <tex>O(\log n)</tex>.
=== Алгоритм за O(1) ===
[[Файл:GlobalandLocalLabelstoConst.jpg|350px|thumb|right|y-fast-tree для меток.]]
Предыдущий алгоритм работает за логарифм из-за того, что слишком часто приходится делать перераспределение меток. Используем <tex>\mathrm{y}{-}\mathrm{fast}{-}\mathrm{trie}</tex> (модифицированный цифровой бор), чтобы улучшить время работы операции добавления до <tex>O(1)</tex>.
65
правок

Навигация