Изменения

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

Сортировка Хана

Нет изменений в размере, 23:53, 20 мая 2014
Переименовка лемм
{{Лемма
|id = lemma3lemma2|about = № 32
|statement =
Выбор <tex>s</tex>-ого наибольшего числа среди <tex>n</tex> чисел, упакованных в <tex>n/g</tex> контейнеров, может быть сделан за время <tex>O(n \log g/g)</tex> и с использованием <tex>O(n/g)</tex> памяти. В том числе, так может быть найдена медиана.
{{Лемма
|id = lemma4lemma3|about = № 43
|statement =
Если <tex>g</tex> целых чисел, в сумме использующих <tex>(\log n)/2</tex> бит, упакованы в один контейнер, тогда <tex>n</tex> чисел в <tex>n/g</tex> контейнерах могут быть отсортированы за время <tex>O((n/g) \log g)</tex> с использованием <tex>O(n/g)</tex> памяти.
{{Лемма
|id = lemma5lemma4|about = № 54
|statement =
Примем, что каждый контейнер содержит <tex> \log m > \log n</tex> бит, и <tex>g</tex> чисел, в каждом из которых <tex>(\log m)/g</tex> бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий <tex>(\log n)/(2g)</tex> бит, и <tex>g</tex> маркеров упакованы в один контейнер таким же образом<tex>^*</tex>, что и числа, тогда <tex>n</tex> чисел в <tex>n/g</tex> контейнерах могут быть отсортированы по их маркерам за время <tex>O((n \log\log n)/g)</tex> с использованием <tex>O(n/g)</tex> памяти.
|proof =
Контейнеры для маркеров могут быть отсортированы с помощью bucket sort потому, что каждый контейнер использует <tex>( \log n)/2</tex> бит. Сортировка сгруппирует контейнеры для чисел как в [[#lemma4lemma3|лемме №4№3]]. Перемещаем каждую группу контейнеров для чисел.
}}
{{Лемма
|id = lemma6lemma5|about = № 65
|statement =
Предположим, что каждый контейнер содержит <tex>\log m \log\log n > \log n</tex> бит, что <tex>g</tex> чисел, в каждом из которых <tex>(\log m)/g</tex> бит, упакованы в один контейнер, что каждое число имеет маркер, содержащий <tex>(\log n)/(2g)</tex> бит, и что <tex>g</tex> маркеров упакованы в один контейнер тем же образом что и числа. Тогда <tex>n</tex> чисел в <tex>n/g</tex> контейнерах могут быть отсортированы по своим маркерам за время <tex>O(n/g)</tex> с использованием <tex>O(n/g)</tex> памяти.
|proof =
Заметим, что несмотря на то, что длина контейнера <tex>\log m \log\log n</tex> бит, всего <tex>\log m</tex> бит используется для хранения упакованных чисел. Так же как в [[#lemma4lemma3|лемме №4№3]] и [[#lemma5lemma4|лемме №5№4]] сортируем контейнеры упакованных маркеров с помощью bucket sort. Для того, чтобы перемещать контейнеры чисел, помещаем <tex>g \log\log n</tex> вместо <tex>g</tex> контейнеров чисел в одну группу. Для транспозиции чисел в группе, содержащей <tex>g \log\log n</tex> контейнеров, упаковываем <tex>g \log\log n</tex> контейнеров в <tex>g</tex>, упаковывая <tex>\log\log n</tex> контейнеров в один. Далее делаем транспозицию над <tex>g</tex> контейнерами. Таким образом перемещение занимает всего <tex>O(g \log\log n)</tex> времени для каждой группы и <tex>O(n/g)</tex> времени для всех чисел. После завершения транспозиции, распаковываем <tex>g</tex> контейнеров в <tex>g \log\log n</tex> контейнеров.
Заметим, что если длина контейнера <tex>\log m \log\log n</tex> и только <tex>\log m</tex> бит используется для упаковки <tex>g \le \log n</tex> чисел в один контейнер, тогда выбор в [[#lemma3lemma2|лемме №3№2]] может быть сделан за время и память <tex>O(n/g)</tex>, потому что упаковка в доказательстве [[#lemma3lemma2|лемме №3№2]] теперь может быть сделана за время <tex>O(n/g)</tex>.
}}
{{Лемма
|id = lemma2lemma6|about = № 26
|statement =
<tex>n</tex> целых чисел можно отсортировать в <tex>\sqrt{n}</tex> наборов <tex>S_{1}</tex>, <tex>S_{2}</tex>, <tex>\ldots</tex>, <tex>S_{\sqrt{n}}</tex> таким образом, что в каждом наборе <tex>\sqrt{n}</tex> чисел и <tex>S_{i}</tex> < <tex>S_{j}</tex> при <tex>i</tex> < <tex>j</tex>, за время <tex>O(n \log\log n/ \log k)</tex> и место <tex>O(n)</tex> с неконсервативным преимуществом <tex>k \log\log n</tex>.
На каждой стадии работаем с одним блоком бит. Назовем эти блоки маленькими числами (далее м.ч.), потому что каждое м.ч. теперь содержит только <tex>\log m/ \log n</tex> бит. Каждое число представлено и соотносится с м.ч., над которым работаем в данный момент. Положим, что нулевая стадия работает с самым большим блоком (блок номер <tex>\log n - 1</tex>). Предполагаем, что биты этих м.ч. упакованы в <tex>n/ \log n</tex> контейнеров с <tex>\log n</tex> м.ч. упакованными в один контейнер. Пренебрегая временем, потраченным на эту упаковку, считаем, что она бесплатна. По [[#lemma3lemma2|лемме №3№2]] находим медиану этих <tex>n</tex> м.ч. за время и память <tex>O(n/ \log n)</tex>. Пусть <tex>a</tex> {{---}} это найденная медиана. Тогда <tex>n</tex> м.ч. могут быть разделены на не более чем три группы: <tex>S_{1}</tex>, <tex>S_{2}</tex> и <tex>S_{3}</tex>. <tex>S_{1}</tex> содержит м.ч., которые меньше <tex>a</tex>, <tex>S_{2}</tex> содержит м.ч., равные <tex>a</tex>, <tex>S_{3}</tex> содержит м.ч., большие <tex>a</tex>. Также мощность <tex>S_{1}</tex> и <tex>S_{3} </tex> не превосходит <tex>n/2</tex>. Мощность <tex>S_{2}</tex> может быть любой. Пусть <tex>S'_{2}</tex> {{---}} это набор чисел, у которых наибольший блок находится в <tex>S_{2}</tex>. Тогда убираем из дальнейшего рассмотрения <tex>\log m/ \log n</tex> бит (наибольший блок) из каждого числа, принадлежащего <tex>S'_{2}</tex>. Таким образом, после первой стадии каждое число находится в наборе размера не большего половины размера начального набора или один из блоков в числе убран из дальнейшего рассмотрения. Так как в каждом числе только <tex>\log n</tex> блоков, для каждого числа потребуется не более <tex>\log n</tex> стадий, чтобы поместить его в набор половинного размера. За <tex>2 \log n</tex> стадий все числа будут отсортированы. Так как на каждой стадии работаем с <tex>n/ \log n</tex> контейнерами, то игнорируя время, необходимое на упаковку м.ч. в контейнеры и помещение м.ч. в нужный набор, затрачивается <tex>O(n)</tex> времени из-за <tex>2 \log n</tex> стадий.
Сложная часть алгоритма заключается в том, как поместить м.ч. в набор, которому принадлежит соответствующее число, после предыдущих операций деления набора в нашем алгоритме. Предположим, что <tex>n</tex> чисел уже поделены в <tex>e</tex> наборов. Используем <tex>\log e</tex> битов чтобы сделать марки для каждого набора. Теперь используем [[#lemma6lemma5|лемме №6№5]]. Полный размер маркера для каждого контейнера должен быть <tex>\log n/2</tex>, и маркер использует <tex>\log e</tex> бит, значит количество маркеров <tex>g</tex> в каждом контейнере должно быть не более <tex>\log n/(2\log e)</tex>. В дальнейшем, так как <tex>g = \log n/(2 \log e)</tex>, м.ч. должны влезать в контейнер. Каждый контейнер содержит <tex>k \log\log n \log n</tex> блоков, каждое м.ч. может содержать <tex>O(k \log n/g) = O(k \log e)</tex> блоков. Заметим, что используется неконсервативное преимущество в <tex>\log\log n</tex> для [[#lemma6lemma5|лемме №6№5]] Поэтому предполагается, что <tex>\log n/(2 \log e)</tex> м.ч., в каждом из которых <tex>k \log e</tex> блоков битов числа, упакованны в один контейнер. Для каждого м.ч. используется маркер из <tex>\log e</tex> бит, который показывает, к какому набору он принадлежит. Предполагаем, что маркеры так же упакованы в контейнеры, как и м.ч. Так как каждый контейнер для маркеров содержит <tex>\log n/(2 \log e)</tex> маркеров, то для каждого контейнера требуется <tex>(\log n)/2</tex> бит. Таким образом, [[#lemma6lemma5|лемма №6№5]] может быть применена для помещения м.ч. в наборы, которым они принадлежат. Так как используется <tex>O((n \log e)/ \log n)</tex> контейнеров, то время, необходимое для помещения м.ч. в их наборы, равно <tex>O((n \log e)/ \log n)</tex>.
Стоит отметить, что процесс помещения нестабилен, т.к. основан на алгоритме из [[#lemma6lemma5|леммы №6№5]].
Стоит отметить, что после нескольких уровней деления размер наборов станет маленьким. Леммы [[#lemma4lemma3|43]], [[#lemma5lemma4|54]], [[#lemma6lemma5|65]] расчитаны на не очень маленькие наборы. Но поскольку сортируется набор из <tex>n</tex> элементов в наборы размера <tex>\sqrt{n}</tex>, то проблем быть не должно.
<tex>k \log\log n</tex> {{---}} это неконсервативное преимущество, <tex>a_{i}</tex>-ые это входящие целые числа в наборе, которые надо отсортировать, <tex>level</tex> это уровень рекурсии.
# Если <tex>(level == 1)</tex> тогда изучаем размер набора. Если размер меньше или равен <tex>\sqrt{n}</tex>, то <tex>return</tex>. Иначе делим этот набор в <tex>\le</tex> 3 набора, используя [[#lemma3lemma2|лемму №3№2]], чтобы найти медиану, а затем используем [[#lemma6lemma5|лемму №6№5]] для сортировки. Для набора, где все элементы равны медиане, не рассматриваем текущий блок и текущим блоком делаем следующий. Создаем маркер, являющийся номером набора для каждого из чисел (0, 1 или 2). Затем направляем маркер для каждого числа назад к месту, где число находилось в начале. Также направляем двубитное число для каждого входного числа, указывающее на текущий блок.
# От <tex>u = 1</tex> до <tex>k</tex>
## Упаковываем <tex>a^{(u)}_{i}</tex>-ый в часть из <tex>1/k</tex>-ых номеров контейнеров. Где <tex>a^{(u)}_{i}</tex> содержит несколько непрерывных блоков, которые состоят из <tex>1/k</tex>-ых битов <tex>a_{i}</tex>. При этом у <tex>a^{(u)}_{i}</tex> текущий блок это самый крупный блок.
## Вызываем Sort(<tex>k \log\log n</tex>, <tex>level - 1</tex>, <tex>a^{(u)}_{0}</tex>, <tex>a^{(u)}_{1}</tex>, <tex>\ldots</tex>, <tex>a^{(u)}_{t}</tex>). Когда алгоритм возвращается из этой рекурсии, маркер, показывающий для каждого числа, к какому набору это число относится, уже направлен назад к месту, где число находится во входных данных. Число, имеющее наибольшее число бит в <tex>a_{i}</tex>, показывающее на текущий блок в нем, так же направлено назад к <tex>a_{i}</tex>.
## Отправляем <tex>a_{i}</tex>-ые к их наборам, используя [[#lemma6lemma5|лемму №6№5]].
Algorithm IterateSort
Так как <tex>q</tex> чисел не надо полностью сортировать и <tex>q = p^2</tex>, то можно использовать [[#lemma2lemma6|лемму №2№6]] для сортировки. Для этого необходимо неконсервативное преимущество, которое получается с помощью signature sorting. Для этого используется линейная техника многократного деления (multi-dividing technique).
После <tex>g</tex> сокращений бит в '''signature sorting''' получаем неконсервативное преимущество в <tex>(h/ \log\log n)^g</tex>. Мы не волнуемся об этих сокращениях до конца потому, что после получения неконсервативного преимущества мы можем переключиться на [[#lemma2lemma6|лемму №2№6]] для завершения разделения <tex>q</tex> чисел с помощью <tex>p</tex> чисел на наборы. Заметим, что по природе битового сокращения начальная задача разделения для каждого набора перешла в <tex>w</tex> подзадач разделения на <tex>w</tex> поднаборов для какого-то числа <tex>w</tex>.
Теперь для каждого набора все его поднаборы в подзадачах собираются в один набор. Затем, используя [[#lemma2lemma6|лемму №2№6]], делается разделение. Так как получено неконсервативное преимущество в <tex>(h/ \log\log n)^g</tex> и работа происходит на уровнях не ниже, чем <tex>2 \log\log\log n</tex>, то алгоритм занимает <tex>O(qt \log\log n/(g(\log h - \log\log\log n) - \log\log\log n)) = O(\log\log n)</tex> времени.
38
правок

Навигация