Изменения

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

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

14 913 байт добавлено, 00:14, 8 июня 2015
Нет описания правки
'''Сортировка Хана ''' (Yijie Han)англ. ''Hansort'' ) {{---}} сложный алгоритм сортировки целых чисел со сложностью <texdpi="130">O(nloglog n \log\log n)</tex>, где <texdpi="130">n</tex> {{---}} количество элементов для сортировки.
Данная статья писалась на основе брошюры Хана(англ. ''Yijie Han''), посвященной этой сортировке. Изложение материала в данной статье идет примерно в том же порядке, в каком она предоставлена в работе Хана.
== Алгоритм Описание ==Алгоритм построен на основе '''экспоненциального поискового дерева Андерсона''' (далее {{---}} Эангл.П.дерево) Андерсона (''Andersson's exponential search tree''). Сортировка происходит за счет вставки целых чисел в Э.П.экспоненциальное поисковое дерево (''далее {{---}} ЭП-дерево'').
== Andersson's exponential search tree Экспоненциальное поисковое дерево Андерсона ==Э.П.дерево с <tex>n</tex> листьями состоит из корня <tex>r</tex> и <tex>n^e</tex> (0<<tex>e</tex><1) Э.П.поддеревьев, в каждом из которых <tex>n^{1 - e}</tex> листьев; каждое Э.П.поддерево является сыном корня <tex>r</tex>. В этом дереве <tex>O(n \log\log n)</tex> уровней. При нарушении баланса дерева, необходимо балансирование, которое требует <tex>O(n \log\log n)</tex> времени при <tex>n</tex> вставленных целых числах. Такое время достигается за счет вставки чисел группами, а не по одиночке, как изначально предлагает Андерссон.
==Необходимая информация==
{{Определение
|id=def1. |definition=Контейнер '''ЭП-дерево''' {{---}} объект определенного типа, содержащий обрабатываемый элемент. Например __int32, __int64это дерево поиска, в котором все ключи хранятся в листьях этого дерева и т.д.}}{{Определение|id=def2. |definition=Алгоритм сортирующий <tex>n</tex> целых чисел из множества <tex>\{0, 1, \ldots, m - 1\}</tex> называется консервативным, если длина контейнера (число бит в контейнере), является <tex>O(\log(m + n))</tex>. Если длина больше, то алгоритм неконсервативный.}}{{Определение|id=def3. |definition=Если мы сортируем целые числа из множества {0, 1, ..., <tex>m</tex> - 1} с длиной контейнера <tex>klog(m + n)</tex> с <tex>k</tex> >= 1, тогда мы сортируем с неконсервативным преимуществом <tex>k</tex>количество детей у каждого узла уменьшается экспоненциально от глубины узла.}}{{Определение|id=def4. |definition=Для множества <tex>S</tex> определимmin(<tex>S</tex>) = min(<tex>a</tex>:<tex>a</tex> принадлежит <tex>S</tex>)max(<tex>S</tex>) = max(<tex>a</tex>:<tex>a</tex> принадлежит <tex>S</tex>)Набор <tex>S1</tex> < <tex>S2</tex> если max(<tex>S1</tex>) <= min(<tex>S2</tex>)
}}
==Уменьшение числа бит в числах==Один из способов ускорить сортировку {{--[[Файл:Exp-}} уменьшить число бит в числеtree. Один из способов уменьшить число бит в числе {{png|400px|thumb|right|Общая структура ЭП-дерева]] Структура ЭП--}} использовать деление пополам дерева: 1) Корень имеет <tex dpi="130">\Theta (n^e)</tex> сыновей <tex dpi="130">(эту идею впервые подал van Emde Boas0 < e < 1 )</tex>. Деление пополам заключается в том, что количество оставшихся бит в числе уменьшается в Все сыновья являются ЭП-деревьями. 2 раза. Это быстрый способ, требующий ) Каждое поддерево корня имеет <texdpi="130">O\Theta(mn^{1-e})</tex> памятисыновей. Для своего дерева Андерссон использует хеширование, что позволяет сократить количество памяти до  В этом дереве <texdpi="130">O(n \log\log n)</tex>уровней. Для того, чтобы еще ускорить алгоритм нам При нарушении баланса дерева необходимо упаковать несколько чисел в один контейнербалансирование, чтобы затем за константное количество шагов произвести хэширование для всех чисел хранимых в контейнере. Для этого используется хэш функция для хэширования которое требует <texdpi="130">O(n \log\log n)</tex> чисел в таблицу размера времени при <texdpi="130">O(n^2)</tex> вставленных целых числах. Такое время достигается за константное времясчет вставки чисел группами, а не поодиночке, без коллизий. Для этого используется хэш модифицированная функция авторства: Dierzfelbinger и Ramanкак изначально предлагал Андерссон.
==Определения== {{ Определение | definition = '''Контейнер''' {{---}} объект, в которым хранятся наши данные. Например: 32-битные и 64-битные числа, массивы, вектора.}}{{ Определение | definition = Алгоритм: Пусть целое число , сортирующий <texdpi="130">b >= 0n</tex> и пусть целых чисел из множества <texdpi="130">U = \{0, 1, \ldots, 2^b m - 1\}</tex>. Класс , называется '''консервативным''', если длина контейнера (число бит в контейнере) равна <texdpi="130">H_{b,s}O(\log(m + n))</tex> хэш функций . Если длина больше, то алгоритм '''неконсервативный'''. }}{{ Определение | definition = Если сортируются целые числа из множества <tex>U</tex> в <texdpi="130">\{0, 1, \ldots, 2^s m - 1\}</tex> определен как с длиной контейнера <texdpi="130">H_{b,s} = k \{h_{a} \mid 0 log (m + n)< a /tex> с < 2^b, a tex dpi="130">k \equiv geqslant 1 (\mod 2)\}</tex> и для всех , тогда сортировка происходит с '''неконсервативным преимуществом''' <tex dpi="130">k</tex>.}}{{ Определение | definition = Для множества <texdpi="130">xS</tex> из определим <texdpi="130">U: h_{a}\min(xS) = (ax \mod 2^b) div 2^min\limits_{b - sa \in S}a</tex>.
Данный алгоритм базируется на следующей лемме:<tex dpi="130">\max(S) = \max\limits_{a \in S} a</tex>
Номер один.{{Лемма|id=lemma1. |statement=Даны целые числа <tex>bНабор </tex> >dpi= <tex>s</tex> "130">= 0 и S1 <tex>TS2</tex> является подмножеством {0, ..., если <tex>2^b</tex> - 1}, содержащим <tex>n</tex> элементов, и <tex>t</tex> >dpi= <tex>2^{-s + 1}</tex>С<tex>^k_{n}</tex>. Функция <tex>h_{a}</tex> принадлежащая <tex>H_{b,s}</tex"130"> может быть выбрана за время <tex>O\max(bn^2S1)</tex> так, что количество коллизий <tex>coll\leqslant \min(h_{a}, TS2) <= t</tex>
}}
Взяв {{ Определение | definition = Предположим, есть набор <texdpi="130">s T</tex> из <tex dpi= 2logn"130">p</tex> мы получим хэш функцию чисел, которые уже отсортированы как <texdpi="130">h_a_{1}, a_{2}, \ldots, a_{ap}</tex> которая захэширует и набор <texdpi="130">nS</tex> чисел из <texdpi="130">Uq</tex> в таблицу размера чисел <texdpi="130">O(n^b_{1}, b_{2)}, \ldots, b_{q}</tex> без коллизий. Очевидно, что Тогда '''разделением''' <texdpi="130">h_{a}(x)q</tex> может быть посчитана для любого чисел <texdpi="130">xp</tex> за константное время. Если мы упакуем несколько чисел в один контейнер так, что они разделены несколькими битами нулей, мы спокойно сможем применить числами называется <texdpi="130">h_{a}p + 1</tex> ко всему контейнерунабор <tex dpi="130">S_{0}, а в результате все хэш значения для всех чисел в контейере были посчитаны. ЗаметимS_{1}, что это возможно только потому\ldots, что в вычисление хэш знчения вовлечены только (mod S_{p}</tex>2^b, где </texdpi="130">) и (div S_{0} < a_{1} < S_{1} < \ldots < a_{p} <tex>2^S_{b - sp}</tex>). }}
Такая хэш функция может быть найдена за <tex>O(n^3)</tex>.==Леммы==
Следует отметить{{Лемма|id = lemma1|about = № 1|statement = Даны целые числа <tex dpi="130">b \geqslant s \geqslant 0</tex>, и <tex dpi="130">T</tex> является подмножеством множества <tex dpi="130">\{0, \ldots, 2^b - 1\}</tex>, содержащим <tex dpi="130">n</tex> элементов, и <tex dpi="130">t \geqslant 2^{-s + 1}С^k_{n}</tex>. Функция <tex dpi="130">h_{a}</tex>, принадлежащая <tex dpi="130">H_{b,s}</tex>, что несмотря на размер таблицы может быть выбрана за время <texdpi="130">O(nbn^2)</tex>так, потребность в памяти не превышает что количество коллизий <texdpi="130">Ocoll(nh_{a}, T)\leqslant t</tex> потому, что хэширование используется только для уменьшения количества бит в числе.}}
{{Лемма|id =lemma2|about =Signature sorting№ 2|statement =Выбор <tex dpi="130">s</tex>-ого наибольшего числа среди <tex dpi="130">n</tex> чисел, упакованных в <tex dpi="150">\frac{n}{g}</tex> контейнеров, может быть сделан за время <tex dpi="150">O(\frac{n \log g}{g})</tex> и с использованием <tex dpi="150">O(\frac{n}{g})</tex> памяти. В данной сортировке используется следующий алгоритм:том числе, так может быть найдена медиана.
Предположим, что |proof = Так как возможно делать попарное сравнение <texdpi="130">ng</tex> чисел должны быть сортированы, и в каждом одном контейнере с <texdpi="130">logmg</tex> бит. Мы рассматриваемчислами в другом и извлекать большие числа из одного контейнера и меньшие из другого за константное время, возможно упаковать медианы из первого, второго, что в каждом числе есть <texdpi="130">h\ldots</tex> сегментов, <tex dpi="130">g</tex>-ого чисел из 5 контейнеров в каждом один контейнер за константное время. Таким образом, набор <tex dpi="130">S</tex> из которых медиан теперь содержится в <texdpi="150">\frac{n}{5g}</tex> контейнерах. Рекурсивно находим медиану <tex dpi="130">log(m</h)tex> в <tex dpi="130">S</tex> бит. Теперь мы применяем хэширование ко всем сегментам и получаем Используя <texdpi="130">2hlognm</tex> бит хэшированных значений для каждого числа. После сортировки на хэшированных значениях для всех начальных чисел начальная задача по сортировке , уберем хотя бы <texdpi="150">\frac{n}{4}</tex> чисел по среди <texdpi="130">mn</tex> бит в каждом стала задачей по сортировке . Затем упакуем оставшиеся из <texdpi="150">\frac{n}{g}</tex> чисел по контейнеров в <texdpi="150">log(m/h)\frac{3n}{4g}</tex> бит в каждомконтейнеров и затем продолжим рекурсию.}}
Так же, рассмотрим проблему последующего разделения. Пусть <tex>a_{1}</tex>, <tex>a_{2}</tex>, ..., <tex>a_{p}</tex> {{---}} Лемма|id = lemma3|about = № 3|statement = Если <texdpi="130">pg</tex> целых чисел и <tex>S</tex> {{---}} множество чисeл. Мы хотим разделить <tex>S</tex> , в сумме использующих <texdpi="150">p + 1</tex> наборов таких, что: <tex>S_\frac{0\log n}</tex> < {<tex>a_{1}</tex>} < <tex>S_{1}</tex> < {<tex>a_{2}</tex>} < ... < {бит, упакованы в один контейнер, тогда <texdpi="130">a_{p}n</tex>} < <tex>S_{p}</tex>. Т.к. мы используем signature sorting, до того как делать вышеописанное разделение, мы поделим биты чисел в <texdpi="150">a_\frac{in}</tex> на <tex>h</tex> сегментов и возьмем некоторые из них. Мы так же поделим биты для каждого числа из <tex>S</tex> и оставим только один в каждом числе. По существу для каждого <tex>a_{ig}</tex> мы возьмем все контейнерах могут быть отсортированы за время <texdpi="150">h</tex> сегментов. Если соответствующие сегменты <tex>a_O(\frac{in \log g}</tex> и <tex>a_{jg})</tex> совпадают, то нам понадобится только один. Сегменты, которые мы берем для числа в с использованием <texdpi="150">S</tex>, O(\frac{{---}n} сегмент, который выделяется из <tex>a_{ig}</tex>. Таким образом мы преобразуем начальную задачу о разделении <tex>n</tex> чисел в <tex>logm</tex> бит в несколько задач на разделение с числами в <tex>log(m/h)</tex> битпамяти.
Пример:
|proof = Так как используется только <texdpi="150">a_\frac{\log n}{12}</tex> бит в каждом контейнере для хранения <tex dpi= 3"130">g</tex> чисел, используем bucket sort, чтобы отсортировать все контейнеры, представляя каждый как число, что занимает <texdpi="150">a_O(\frac{n}{g})</tex> времени и памяти. Так как используется <tex dpi="150">\frac{\log n}{2}</tex> = 5бит на контейнер, понадобится <texdpi="130">a_\sqrt{3n}</tex> = 7, шаблонов для всех контейнеров. Затем поместим <texdpi="150">a_g < \frac{4\log n}{2}</tex> контейнеров с одинаковым шаблоном в одну группу. Для каждого шаблона останется не более <tex dpi= 10"130">g - 1</tex> контейнеров, S которые не смогут образовать группу. Поэтому не более <tex dpi= "130">\sqrt{n}(g - 1)</tex> контейнеров не смогут сформировать группу. Для каждой группы помещаем <tex dpi="130">i</tex>-е число во всех <tex dpi="130">g</tex> контейнерах в один. Таким образом берутся <tex dpi="130">g</tex> <tex dpi="130">g</tex>-целых векторов и получаются <tex dpi="130">g</tex> <tex dpi="130">g</tex>-целых векторов, 4где <tex dpi="130">i</tex>-ый вектор содержит <tex dpi="130">i</tex>-ое число из входящего вектора. Эта транспозиция может быть сделана за время <tex dpi="130">O(g \log g)</tex>, 6с использованием <tex dpi="130">O(g)</tex> памяти. Для всех групп это занимает время <tex dpi="150">O(\frac{n \log g}{g})</tex>, 8, 9, 13, 14с использованием <tex dpi="150">O(\frac{n}{g})</tex> памяти.
Мы разделим числа на 2 сегмента. Для контейнеров вне групп (которых <texdpi="130">a_\sqrt{n}(g - 1})</tex> получим верхний сегмент 0, нижний 3; штук) разбираем и собираем заново контейнеры. На это потребуется не более <texdpi="150">a_O(\frac{2n}</tex> верхний 1, нижний 1; <tex>a_{3g})</tex> верхний 1, нижний 3; <tex>a_{4}</tex> верхний 2, нижний 2времени и памяти. Для элементов из S получим: После всего этого используем карманную сортировку вновь для 1: нижний 1 т.к. он выделяется из нижнего сегмента сортировки <texdpi="130">a_{1}n</tex>; для 4 нижний 0; для 8 нижний 0; для 9 нижний 1; для 13 верхний 3; для 14 верхний 3контейнеров. Теперь Таким образом, все верхние сегменты, нижние сегменты 1 и 3, нижние сегменты 4, 5, 6, 7, нижние сегменты 8, 9, 10 формируют 4 новые задачи на разделениечисла отсортированы.
==Сортировка на маленьких целых==
Для лучшего понимания действия алгоритма и материала, изложенного в данной статье, в целом, ниже представлены несколько полезных лемм.
Номер два.{{Лемма|id=lemma2. |statement=<tex>n</tex> целых чисел можно отсортировать в Заметим, что когда <texdpi="130">g = O( \sqrt{log n}</tex> наборов <tex>S_{1})</tex>, сортировка <texdpi="130">S_{2}O(n)</tex>, ..., чисел в <texdpi="150">S_{\sqrtfrac{n}{g}</tex> таким образом, что в каждом наборе контейнеров произойдет за время <texdpi="150">O((\sqrtfrac{n}</tex> чисел и <tex>S_{i}</tex> < <tex>S_{jg})</tex> при <texdpi="130">i</tex> < <tex>j</tex>, за время <tex>O(nloglogn/logk\log\log n)</tex> и место с использованием <texdpi="150">O(\frac{n}{g})</tex> с не консервативным преимуществом <tex>kloglogn</tex>|proof=Доказательство данной леммы будет приведено далее в тексте статьипамяти. Выгода очевидна.
}}
Номер три.
{{Лемма
|id=lemma3. lemma4|about = № 4|statement=Выбор Примем, что каждый контейнер содержит <texdpi="130"> \log m >s\log n</tex>-ого наибольшего числа среди бит, и <texdpi="130">ng</tex> чисел упакованных , в каждом из которых <texdpi="150">n/\frac{\log m}{g}</tex> контейнеров может быть сделана за бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий <texdpi="150">O(nlogg/g)\frac{\log n}{2g}</tex> время бит, и с использованием <texdpi="130">O(n/g)</tex> места. Конкретно медиана может быть так найдена.|proof=Так как мы можем делать попарное сравнение маркеров упакованы в один контейнер таким же образом<texdpi="130">g^*</tex> чисел в одном контейнере с , что и числа, тогда <texdpi="130">gn</tex> числами чисел в другом и извлекать большие числа из одного контейнера и меньшие из другого за константное время, мы можем упаковать медианы из первого, второго, ..., <texdpi="150">\frac{n}{g}</tex>-ого чисел из 5 контейнеров в один контейнер контейнерах могут быть отсортированы по их маркерам за константное время. Таким образом набор <texdpi="150">SO(\frac{n \log\log n}{g})</tex> из медиан теперь содержится в с использованием <texdpi="150">O(\frac{n/(5g}{g})</tex> контейнерахпамяти. Рекурсивно находим медиану (*): если число <texdpi="130">ma</tex> в упаковано как <texdpi="130">Ss</tex>. Используя -ое число в <texdpi="130">mt</tex> уберем хотя бы -ом контейнере для чисел, тогда маркер для <texdpi="130">n/4a</tex> чисел среди упакован как <texdpi="130">ns</tex>. Затем упакуем оставшиеся из -ый маркер в <texdpi="130">n/gt</tex> контейнеров в -ом контейнере для маркеров.  |proof = Контейнеры для маркеров могут быть отсортированы с помощью bucket sort потому, что каждый контейнер использует <texdpi="150">3n/4g\frac{\log n}{2}</tex> бит. Сортировка сгруппирует контейнеры для чисел как в [[#lemma3|лемме №3]]. Перемещаем каждую группу контейнеров и затем продолжим рекурсиюдля чисел.
}}
Номер четыре.
{{Лемма
|id=lemma4.lemma5|about = № 5|statement=Если <tex>g</tex> целых чиселПредположим, в сумме использующие <tex>(logn)/2</tex> бит, упакованы в один что каждый контейнер, тогда содержит <texdpi="130">\log m \log\log n</tex> чисел в <tex>\log n/g</tex> контейнерах могут быть отсортированы за время бит, что <texdpi="130">O((n/g)logg)</tex>чисел, с использованием <tex>O(n/g)</tex> места.|proof=Так как используется только <tex>(logn)/2</tex> бит в каждом контейнере для хранения из которых <texdpi="150">\frac{\log m}{g}</tex> чиселбит, мы можем использовать bucket sorting чтобы отсортировать все контейнеры. представляя каждый как числоупакованы в один контейнер, что занимает <tex>O(n/g)</tex> времени и места. Потомукаждое число имеет маркер, что мы используем <tex>(logn)/2</tex> бит на контейнер нам понадобится содержащий <texdpi="150">\sqrt frac{\log n}{2g}</tex> шаблонов для всех контейнеров. Затем поместим бит, и что <texdpi="130">g < (logn)/2</tex> контейнеров с одинаковым шаблоном маркеров упакованы в одну группуодин контейнер тем же образом что и числа. Для каждого шаблона останется не более Тогда <texdpi="130">g - 1n</tex> контейнеров которые не смогут образовать группу. Поэтому не более чисел в <texdpi="150">\sqrtfrac{n}(g - 1)</tex> контейнеров не смогут сформировать группу. Для каждой группы мы помещаем <tex>i</tex>-е число во всех <tex>{g}</tex> контейнерах в один. Таким образом мы берем <tex>g</tex> <tex>g</tex>-целых векторов и получаем <tex>g</tex> <tex>g</tex>-целых векторов где <tex>i</tex>-ый вектор содержит <tex>i</tex>-ое число из входящего вектора. Эта транспозиция может могут быть сделана отсортированы по своим маркерам за время <texdpi="150">O(glogg)</tex>, с использованием <tex>O(g)</tex> места. Для всех групп это занимает время <tex>O((\frac{n/}{g)logg})</tex>, с использованием <texdpi="150">O(\frac{n/}{g})</tex> местапамяти.
|proof = Заметим, что несмотря на то, что длина контейнера <tex dpi="130">\log m \log\log n</tex> бит, всего <tex dpi="130">\log m</tex> бит используется для хранения упакованных чисел. Так же как в [[#lemma3|лемме №3]] и [[#lemma4|лемме №4]] сортируем контейнеры упакованных маркеров с помощью bucket sort. Для того, чтобы перемещать контейнеры чисел, помещаем <tex dpi="130">g \log\log n</tex> вместо <tex dpi="130">g</tex> контейнеров чисел в одну группу. Для транспозиции чисел в группе, содержащей <tex dpi="130">g \log\log n</tex> контейнеров, упаковываем <tex dpi="130">g \log\log n</tex> контейнеров вне групп (которых в <tex dpi="130">g</tex>, упаковывая <texdpi="130">\sqrt(log\log n)</tex> контейнеров в один. Далее делаем транспозицию над <tex dpi="130">g</tex> контейнерами. Таким образом перемещение занимает всего <tex dpi="130">O(g - 1\log\log n)</tex> штук) мы просто разберем времени для каждой группы и соберем заново контейнеры. На это потребуется не более <texdpi="150">O(\frac{n/}{g})</tex> места и временидля всех чисел. После всего этого мы используем bucket sorting вновь для сортировки завершения транспозиции, распаковываем <tex dpi="130">g</tex> контейнеров в <texdpi="130">g \log\log n</tex> контейнеров. таким образом мы отсортируем все числа.}}
Заметим, что когда <tex>g = O(logn)</tex> мы сортируем <tex>O(n)</tex> чисел в <tex>n/g</tex> контейнеров за время <tex>O((n/g)loglogn)</tex>, с использованием O(n/g) места. Выгода очевидна.
Лемма пять.{{Лемма|id=lemma5.|statement=Если принятьЗаметим, что каждый контейнер содержит если длина контейнера <texdpi="130">logm > logn\log m \log\log n</tex> бит, и только <texdpi="130">g</tex> чисел, в каждом из которых <tex>(logm)/g\log m</tex> бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий <tex>(logn)/(2g)</tex> бит, и используется для упаковки <texdpi="130">g\leqslant \log n</tex> маркеров упакованы чисел в один контейнер таким же образом<tex>^*</tex>, что и числа, тогда <tex>n</tex> чисел выбор в <tex>n/g</tex> контейнерах могут [[#lemma2|лемме №2]] может быть отсортированы по их маркерам сделан за время и память <texdpi="150">O((nloglogn)/g)</tex> с использованием <tex>O(\frac{n/}{g})</tex> места.(*): если число <tex>a</tex> упаковано как <tex>s</tex>-ое число в <tex>t</tex>-ом контейнере для чисел, тогда маркер для <tex>a</tex> упакован как <tex>s</tex>-ый маркер потому что упаковка в <tex>t</tex>-ом контейнере для маркеров.доказательстве [[#lemma2|proof=Контейнеры для маркеров могут лемме №2]] теперь может быть отсортированы с помощью bucket sort потому, что каждый контейнер использует сделана за время <texdpi="150">O(logn\frac{n}{g})/2</tex> бит. Сортировка сгруппирует контейнеры для чисел как в четвертой лемме. Мы можем переместить каждую группу контейнеров для чисел.
}}
Заметим, что сортирующие алгоритмы в четвертой и пятой леммах нестабильные. Хотя на их основе можно построить стабильные алгоритмы используя известный метод добавления адресных битов к каждому входящему числу.
Если у нас длина контейнеров больше, сортировка может быть ускорена, как показано в следующей лемме.
Лемма шесть.
{{Лемма
|id=lemma6.|about = № 6|statement=предположим, что каждый контейнер содержит <texdpi="130">logmloglogn > logn</tex> бит, что <tex>gn</tex> целых чисел, можно отсортировать в каждом из которых <texdpi="130">(logm)/g\sqrt{n}</tex> бит, упакованы в один контейнер, что каждое число имеет маркер, содержащий наборов <texdpi="130">(logn)/(2g)S_{1}</tex> бит, и что <texdpi="130">gS_{2}</tex> маркеров упакованы в один контейнер тем же образом что и числа, тогда <texdpi="130">n</tex> чисел в <tex>n/g</tex> контейнерах могут быть отсортированы по своим маркерам за время <tex>O(n/g)\ldots</tex>, с использованием <texdpi="130">O(S_{\sqrt{n/g)}}</tex> памяти.|proof=Заметимтаким образом, что несмотря на то, что длина контейнера в каждом наборе <texdpi="130">logmloglogn</tex> бит всего <tex>logm\sqrt{n}</tex> бит используется для хранения упакованных чисел. Так же как в леммах четыре и пять мы сортируем контейнеры упакованных маркеров с помощью bucket sort. Для того, чтобы перемещать контейнеры чисел мы помещаем <texdpi="130">gloglognS_{i} </tex> вместо <tex>gS_{j}</tex> контейнеров чисел в одну группу. Для транспозиции чисел в группе содержащей при <texdpi="130">gloglogn</tex> контейнеров мы сначала упаковываем i <tex>gloglognj</tex> контейнеров в <tex>g</tex> контейнеров упаковывая <tex>loglogn</tex> контейнеров в один. Далее мы делаем транспозицию над <tex>g</tex> контейнерами. Таким образом перемещение занимает всего , за время <texdpi="150">O(gloglogn\frac{n \log\log n} {\log k})</tex> времени для каждой группы и место <texdpi="130">O(n/g)</tex> времени для всех чисел. После завершения транспозиции, мы далее распаковываем с неконсервативным преимуществом <texdpi="130">gk \log\log n</tex> контейнеров в <tex>gloglogn</tex> контейнеров.}}
Заметим, что если длина контейнера |proof = Алгоритм сортировки <texdpi="130">logmloglogn</tex> и только <tex>logm</tex> бит используется для упаковки <tex>g <= lognn</tex> целых чисел в один контейнер, тогда выбор в лемме три может быть сделан за время и место <texdpi="130">O(\sqrt{n/g)}</tex>наборов, потомупредставленный ниже, что упаковка в доказатльстве является доказательством данной леммы три теперь может быть сделана за время <tex>O(n/g)</tex>.
==Сортировка n целых чисел в sqrt(n) наборов==
Постановка задачи и решение некоторых проблем:
Рассмотрим проблему сортировки <tex>n</tex> целых чисел из множества {0, 1, ..., <tex>m</tex> - 1} в <tex>\sqrt{n}</tex> наборов как во второй лемме. Мы предполагаем, что в каждом контейнере <tex>kloglognlogm</tex> бит и хранит число в <tex>logm</tex> бит. Поэтому неконсервативное преимущество <tex>kloglogn</tex>. Мы так же предполагаем, что <tex>logm >= lognloglogn</tex>. Иначе мы можем использовать radix sort для сортировки за время <tex>O(nloglogn)</tex> и линейную память. Мы делим <tex>logm</tex> бит, используемых для представления каждого числа, в <tex>logn</tex> блоков. Таким образом каждый блок содержит как минимум <tex>loglogn</tex> бит. <tex>i</tex>-ый блок содержит с <tex>ilogm/logn</tex>-ого по <tex>((i + 1)logm/logn - 1)</tex>-ый биты. Биты считаются с наименьшего бита начиная с нуля. Теперь у нас имеется <tex>2logn</tex>-уровневый алгоритм, который работает следующим образом:
 
На каждой стадии мы работаем с одним блоком бит. Назовем эти блоки маленькими числами (далее м.ч.) потому, что каждое м.ч. теперь содержит только <tex>logm/logn</tex> бит. Каждое число представлено и соотносится с м.ч., над которым мы работаем в данный момент. Положим, что нулевая стадия работает с самыми большим блоком (блок номер <tex>logn - 1</tex>). Предполагаем, что биты этих м.ч. упакованы в <tex>n/logn</tex> контейнеров с <tex>logn</tex> м.ч. упакованных в один контейнер. Мы пренебрегаем временем, потраченным на на эту упаковку, считая что она бесплатна. По третьей лемме мы можем найти медиану этих <tex>n</tex> м.ч. за время и память <tex>O(n/logn)</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>logm/logn</tex> бит (наибольший блок) из каждого числа из <tex>S'_{2}</tex> из дальнейшего рассмотрения. Таким образом после первой стадии каждое число находится в наборе размера не большего половины размера начального набора или один из блоков в числе убран из дальнейшего рассмотрения. Так как в каждом числе только <tex>logn</tex> блоков, для каждого числа потребуется не более <tex>logn</tex> стадий чтобы поместить его в набор половинного размера. За <tex>2logn</tex> стадий все числа будут отсортированы. Так как на каждой стадии мы работаем с <tex>n/logn</tex> контейнерами, то игнорируя время, необходимое на упаковку м.ч. в контейнеры и помещение м.ч. в нужный набор, мы затратим <tex>O(n)</tex> времени из-за <tex>2logn</tex> стадий.
Сложная часть алгоритма заключается в том, как поместить маленькие числа в набор, которому принадлежит соответствующее число, после предыдущих операций деления набора в нашем алгоритме. Предположим, что Рассмотрим проблему сортировки <texdpi="130">n</tex> целых чисел уже поделены в из множества <texdpi="130">e\{0, 1, \ldots, m - 1\}</tex> наборов. Мы можем использовать в <texdpi="130">loge\sqrt{n}</tex> битов чтобы сделать марки для каждого наборанаборов, как в условии леммы. Теперь хотелось бы использовать лемму шесть. Полный размер маркера для каждого контейнера должен быть <tex>logn/2</tex>Предполагаем, и маркер использует что каждый контейнер содержит <texdpi="130">logek \log\log n \log m</tex> бит, количество маркеров <tex>g</tex> и хранит число в каждом контейнере должно быть не более <texdpi="130">logn/(2loge)\log m</tex>бит. В дальнейшем т.к. Поэтому неконсервативное преимущество {{---}} <texdpi="130">g = logn/(2loge)k \log \log n</tex> м.ч. должны влезать в контейнер. Каждый контейнер содержит Также предполагаем, что <texdpi="130">kloglognlogn\log m \geqslant \log n \log\log n</tex> блоков, каждое м.ч. может содержать Иначе можно использовать radix sort для сортировки за время <texdpi="130">O(klogn/g) = O(klogen \log\log n)</tex> блокови линейную память. Заметим, что мы используем неконсервативное преимущество в Делим <texdpi="130">loglogn\log m</tex> бит, используемых для использования леммы шесть. Поэтому мы предполагаем что <tex>logn/(2loge)</tex> м.ч. представления каждого числа, в каждом из которых <texdpi="130">kloge\log n</tex> блоков битов числа упакованный в один контейнер. Для каждого м.ч. мы используем маркер из Таким образом, каждый блок содержит как минимум <texdpi="130">loge\log\log n</tex> бит, который показывает к какому набору он принадлежит. Предполагаем, что маркеры так же упакованы в контейнеры как и м.ч. Так как каждый контейнер для маркеров содержит <texdpi="130">logn/(2loge)i</tex> маркеров, то для каждого контейнера требуется -ый блок содержит с <texdpi="150">(logn)/2\frac{i \log m} {\log n}</tex> бит. Таким образом лемма шесть может быть применена для помещения м.ч. в наборы, которым они принадлежат. Так как используется -ого по <texdpi="150">O(\frac{(nlogei + 1)/logn\log m} {\log n - 1})</tex> контейнеров то время необходимое для помещения м-ый биты.чБиты считаются с наименьшего бита, начиная с нуля. в их наборы потребуется Теперь у нас имеется <texdpi="130">O((nloge)/logn)2 \log n</tex> времени.-уровневый алгоритм, который работает следующим образом:
Стоит отметить, что процесс помещения нестабилен, т.к. основан на алгоритме из леммы шесть.
При таком помещении мы сразу сталкиваемся со следующей проблемойНа каждой стадии работаем с одним блоком бит. Назовем эти блоки маленькими числами (далее м.ч.), потому что каждое м.ч. теперь содержит только <tex dpi="150">\frac{\log m}{\log n}</tex> бит. Каждое число представлено и соотносится с м.ч., над которым работаем в данный момент. Положим, что нулевая стадия работает с самым большим блоком (блок номер <tex dpi="130">\log n - 1</tex>). Предполагаем, что биты этих м.ч. упакованы в <tex dpi="150">\frac{n}{\log n}</tex> контейнеров с <tex dpi="130">\log n</tex> м.ч. упакованными в один контейнер. Пренебрегая временем, потраченным на эту упаковку, считаем, что она бесплатна. По [[#lemma2|лемме №2]] находим медиану этих <tex dpi="130">n</tex> м.ч. за время и память <tex dpi="150">O(\frac{n}{\log n})</tex>. Пусть <tex dpi="130">a</tex> {{---}} это найденная медиана. Тогда <tex dpi="130">n</tex> м.ч. могут быть разделены на не более чем три группы: <tex dpi="130">S_{1}</tex>, <tex dpi="130">S_{2}</tex> и <tex dpi="130">S_{3}</tex>. <tex dpi="130">S_{1}</tex> содержит м.ч., которые меньше <tex dpi="130">a</tex>, <tex dpi="130">S_{2}</tex> содержит м.ч., равные <tex dpi="130">a</tex>, <tex dpi="130">S_{3}</tex> содержит м.ч., большие <tex dpi="130">a</tex>. Также мощность <tex dpi="130">S_{1}</tex> и <tex dpi="130">S_{3} </tex> не превосходит <tex dpi="130">n/2</tex>. Мощность <tex dpi="130">S_{2}</tex> может быть любой. Пусть <tex dpi="130">S'_{2}</tex> {{---}} это набор чисел, у которых наибольший блок находится в <tex dpi="130">S_{2}</tex>. Тогда убираем из дальнейшего рассмотрения <tex dpi="150">\frac{\log m}{\log n}</tex> бит (наибольший блок) из каждого числа, принадлежащего <tex dpi="130">S'_{2}</tex>. Таким образом, после первой стадии каждое число находится в наборе размера не большего половины размера начального набора или один из блоков в числе убран из дальнейшего рассмотрения. Так как в каждом числе только <tex dpi="130">\log n</tex> блоков, для каждого числа потребуется не более <tex dpi="130">\log n</tex> стадий, чтобы поместить его в набор половинного размера. За <tex dpi="130">2 \log n</tex> стадий все числа будут отсортированы. Так как на каждой стадии работаем с <tex dpi="150">\frac{n}{\log n}</tex> контейнерами, то игнорируя время, необходимое на упаковку м.ч. в контейнеры и помещение м.ч. в нужный набор, затрачивается <tex dpi="130">O(n)</tex> времени из-за <tex dpi="130">2 \log n</tex> стадий.
Рассмотрим число <tex>a</tex>, которое является <tex>i</tex>-ым в наборе <tex>S</tex>. Рассмотрим блок <tex>a</tex> (назовем его <tex>a'</tex>), который является <tex>i</tex>-ым м.ч. в <tex>S</tex>. Когда мы используем вышеописанный метод перемещения нескольких следующих блоков <tex>a</tex> (назовем это <tex>a''</tex>) в <tex>S</tex>, <tex>a''</tex> просто перемещен на позицию в наборе <tex>S</tex>, но не обязательно на позицию <tex>i</tex> (где расположен <tex>a'</tex>). Если значение блока <tex>a'</tex> одинаково для всех чисел в <tex>S</tex>, то это не создаст проблемы потому, что блок одинаков вне зависимости от того в какое место в <tex>S</tex> помещен <tex>a''</tex>. Иначе у нас возникает проблема дальнейшей сортировки. Поэтому мы поступаем следующим образом: На каждой стадии числа в одном наборе работают на общем блоке, который назовем "текущий блок набора". Блоки, которые предшествуют текущему блоку содержат важные биты и идентичны для всех чисел в наборе. Когда мы помещаем больше бит в набор мы помещаем последующие блоки вместе с текущим блоком в набор. Так вот, в вышеописанном процессе помещения мы предполагаем, что самый значимый блок среди <tex>kloge</tex> блоков это текущий блок. Таким образом после того как мы поместили эти <tex>kloge</tex> блоков в набор мы удаляем изначальный текущий блок, потому что мы знаем, что эти <tex>kloge</tex> блоков перемещены в правильный набор и нам не важно где находился начальный текущий блок. Тот текущий блок находится в перемещенных <tex>kloge</tex> блоках.
Стоит отметитьСложная часть алгоритма заключается в том, как поместить м.ч. в набор, которому принадлежит соответствующее число, что после нескольких уровней предыдущих операций деления размер набора в нашем алгоритме. Предположим, что <tex dpi="130">n</tex> чисел уже поделены в <tex dpi="130">e</tex> наборов станет маленьким. Леммы четыреИспользуем <tex dpi="130">\log e</tex> битов чтобы сделать марки для каждого набора. Теперь используем [[#lemma5|лемме №5]]. Полный размер маркера для каждого контейнера должен быть <tex dpi="150">\frac{\log n}{2}</tex>, пять и шесть расчитанны на маркер использует <tex dpi="130">\log e</tex> бит, значит количество маркеров <tex dpi="130">g</tex> в каждом контейнере должно быть не очень маленькие наборыболее <tex dpi="150">\frac{\log n}{2\log e}</tex>. В дальнейшем, так как <tex dpi="150">g = \frac{\log n}{2 \log e}</tex>, м.ч. должны влезать в контейнер. Каждый контейнер содержит <tex dpi="130">k \log\log n \log n</tex> блоков, каждое м.ч. может содержать <tex dpi="150">O(\frac{k \log n}{g}) = O(k \log e)</tex> блоков. Заметим, что используется неконсервативное преимущество в <tex dpi="130">\log\log n</tex> для [[#lemma5|лемме №5]] Поэтому предполагается, что <tex dpi="150">\frac{\log n}{2 \log e}</tex> м.ч., в каждом из которых <tex dpi="130">k \log e</tex> блоков битов числа, упакованны в один контейнер. Для каждого м.ч. Но поскольку мы сортируем набор используется маркер из <tex dpi="130">\log e</tex> бит, который показывает, к какому набору он принадлежит. Предполагаем, что маркеры так же упакованы в контейнеры, как и м.ч. Так как каждый контейнер для маркеров содержит <tex dpi="150">\frac{\log n}{2 \log e}</tex>маркеров, то для каждого контейнера требуется <tex dpi="150">\frac{\log n}{2}</tex> элементов бит. Таким образом, [[#lemma5|лемма №5]] может быть применена для помещения м.ч. в наборы размера , которым они принадлежат. Так как используется <texdpi="150">O(\sqrtfrac{n\log e}{ \log n})</tex>контейнеров, то проблем не должно бытьвремя, необходимое для помещения м.ч. в их наборы, равно <tex dpi="150">O(\frac{n \log e}{ \log n})</tex>.
Собственно алгоритм:Стоит отметить, что процесс помещения нестабилен, т.к. основан на алгоритме из [[#lemma5|леммы №5]].
Algorithm Sort(<tex>kloglogn</tex>, <tex>level</tex>, <tex>a_{0}</tex>, <tex>a_{1}</tex>, ..., <tex>a_{t}</tex>)
<tex>kloglogn</tex> это неконсервативное преимущество, <tex>a_{i}</tex>-ые это входящие целые числа в наборе, которые надо отсортировать, <tex>level</tex> это уровень рекурсииПри таком помещении сразу возникает следующая проблема.
1Рассмотрим число <tex dpi="130">a</tex>, которое является <tex dpi="130">i</tex>-ым в наборе <tex dpi="130">S</tex>. Рассмотрим блок <tex dpi="130">a</tex> (назовем его <tex dpi="130">a'</tex>) , который является <tex dpi="130">i</tex>-ым м.ч. в <tex dpi="130">S</tex>. Когда используется вышеописанный метод перемещения нескольких следующих блоков <tex dpi="130">a</tex> (назовем это <tex dpi="130">a''</tex>) в <tex dpi="130">S</tex>, <tex dpi="130">a''</tex> просто перемещен на позицию в наборе <tex dpi="130">S</tex>, но не обязательно на позицию <tex dpi="130">i</tex> (где расположен <tex dpi="130">a'</tex>). Если значение блока <tex dpi="130">a'</tex> одинаково для всех чисел в <tex dpi="130">S</tex>, то это не создаст проблемы потому, что блок одинаков вне зависимости от того в какое место в <tex dpi="130">S</tex> помещен <tex dpi="130">a''</tex>. Иначе у нас возникает проблема дальнейшей сортировки. Поэтому поступаем следующим образом: На каждой стадии числа в одном наборе работают на общем блоке, который назовем "текущий блок набора". Блоки, которые предшествуют текущему блоку содержат важные биты и идентичны для всех чисел в наборе. Когда помещаем больше бит в набор, последующие блоки помещаются в набор вместе с текущим блоком. Так вот, в вышеописанном процессе помещения предполагается, что самый значимый блок среди <tex dpi="130">k \log e</tex> блоков {{---}} это текущий блок. Таким образом, после того, как эти <tex dpi="130">k \log e</tex> блоков помещены в набор, изначальный текущий блок удаляется, потому что известно, что эти <tex dpi="130">k \log e</tex> блоков перемещены в правильный набор, и нам не важно где находился начальный текущий блок. Тот текущий блок находится в перемещенных <tex dpi="130">k \log e</tex> блоках.
<tex>if level == 1</tex> тогда изучить размер набора. Если размер меньше или равен <tex>\sqrt{n}</tex>, то <tex>return</tex>. Иначе разделить этот набор в <= 3 набора используя лемму три, чтобы найти медиану а затем использовать лемму 6 для сортировки. Для набора где все элементы равны медиане, не рассматривать текущий блок и текущим блоком сделать следующий. Создать маркер, являющийся номером набора для каждого из чисел (0, 1 или 2). Затем направьте маркер для каждого числа назад к месту, где число находилось в начале. Также направьте двубитное число для каждого входного числа, указывающее на текущий блок. <tex>Return</tex>.
2) Стоит отметить, что после нескольких уровней деления размер наборов станет маленьким. Леммы [[#lemma3|3]], [[#lemma4|4]], [[#lemma5|5]] расчитаны на не очень маленькие наборы. Но поскольку сортируется набор из <tex dpi="130">n</tex> элементов в наборы размера <tex dpi="130">\sqrt{n}</tex>, то проблем быть не должно.
От <tex>u = 1</tex> до <tex>k</tex>
2.1) Упаковать <tex>a^{(u)}_{i}</tex>-ый в часть из <tex>1/k</tex>-ых номеров контейнеров, где <tex>a^{(u)}_{i}</tex> содержит несколько непрерывных блоков, которые состоят из <tex>1/k</tex>-ых битов <tex>a_{i}</tex> и у которого текущий блок это самый крупный блок.===Алгоритм сортировки===
2.2) Вызвать Sort(Algorithm <tex>kloglognSort(advantage</tex>, <tex>level - 1</tex>, <tex>a^{(u)}_a_{0}</tex>, <tex>a^{(u)}_a_{1}</tex>, ..., <tex>a^{(u)}_{t}</tex>). Когда алгоритм возвращается из этой рекурсии, маркер, показывающий для каждого числа, к которому набору это число относится, уже отправлен назад к месту где число находится во входных данных. Число имеющее наибольшее число бит в <tex>a_{i}\ldots</tex>, показывающее на ткущий блок в нем, так же отправлено назад к <tex>a_{it}</tex>.)
2.3) Отправить <tex>advantage</tex> {{---}} это неконсервативное преимущество равное <tex>k\log\log n</tex>, <tex>a_{i}</tex>-ые к их наборамэто входящие целые числа в наборе, которые надо отсортировать, используя лемму шесть.<tex>level</tex>это уровень рекурсии.
end# Если <tex>level</tex> равен <tex>1</tex> тогда изучаем размер набора. Если размер меньше или равен <tex>\sqrt{n}</tex>, то <tex>return</tex>. Иначе делим этот набор в <tex>\leqslant</tex> 3 набора, используя [[#lemma2|лемму №2]], чтобы найти медиану, а затем используем [[#lemma5|лемму №5]] для сортировки. Для набора, где все элементы равны медиане, не рассматриваем текущий блок и текущим блоком делаем следующий. Создаем маркер, являющийся номером набора для каждого из чисел (0, 1 или 2). Затем направляем маркер для каждого числа назад к месту, где число находилось в начале. Также направляем двубитное число для каждого входного числа, указывающее на текущий блок.# От <tex dpi="130">u = 1</tex> до <tex dpi="130">k</tex>## Упаковываем <tex dpi="130">a^{(u)}_{i}</tex>-ый в часть из <tex dpi="130">1/k</tex>-ых номеров контейнеров. Где <tex dpi="130">a^{(u)}_{i}</tex> содержит несколько непрерывных блоков, которые состоят из <tex dpi="150">\frac{1}{k}</tex>-ых битов <tex dpi="130">a_{i}</tex>. При этом у <tex dpi="130">a^{(u)}_{i}</tex> текущий блок это самый крупный блок.## Вызываем <tex>Sort(advantage</tex>, <tex>level - 1</tex>, <tex dpi="130">a^{(u)}_{0}</tex>, <tex dpi="130">a^{(u)}_{1}</tex>, <tex>\ldots</tex>, <tex dpi="130">a^{(u)}_{t}</tex>). Когда алгоритм возвращается из этой рекурсии, маркер, показывающий для каждого числа, к какому набору это число относится, уже направлен назад к месту, где число находится во входных данных. Число, имеющее наибольшее число бит в <tex dpi="130">a_{i}</tex>, показывающее на текущий блок в нем, так же направлено назад к <tex dpi="130">a_{i}</tex>.## Отправляем <tex dpi="130">a_{i}</tex>-ые к их наборам, используя [[#lemma5|лемму №5]].
Algorithm IterateSort
Call Sort(<tex>kloglognSort(advantage</tex>, <texdpi="130">\log_{k}((logn\log n)/4)</tex>, <texdpi="130">a_{0}</tex>, <texdpi="130">a_{1}</tex>, ...<tex dpi="130">\ldots</tex>, <texdpi="130">a_{n - 1}</tex>);
от 1 до 5
# Помещаем <tex dpi="130">a_{i}</tex> в соответствующий набор с помощью блочной сортировки (англ. ''bucket sort''), потому что наборов около <tex dpi="130">\sqrt{n}</tex>.
# Для каждого набора <tex dpi="130">S = </tex>{<tex dpi="130">a_{i_{0}}, a_{i_{1}}, \ldots, a_{i_{t}}</tex>}, если <tex dpi="130">t > \sqrt{n}</tex>, вызываем <tex>Sort(advantage</tex>, <tex dpi="130">\log_{k}(\frac{\log n}{4})</tex>, <tex dpi="130">a_{i_{0}}, a_{i_{1}}, \ldots, a_{i_{t}}</tex>).
 
Время работы алгоритма <tex dpi="150">O(\frac{n \log\log n}{\log k})</tex>, что доказывает лемму.
}}
 
 
 
==Уменьшение числа бит в числах==
Один из способов ускорить сортировку {{---}} уменьшить число бит в числе. Один из способов уменьшить число бит в числе {{---}} использовать деление пополам (эту идею впервые подал van Emde Boas). Деление пополам заключается в том, что количество оставшихся бит в числе уменьшается в 2 раза. Это быстрый способ, требующий <tex dpi="130">O(m)</tex> памяти. Для своего дерева Андерссон использует хеширование, что позволяет сократить количество памяти до <tex dpi="130">O(n)</tex>. Для того чтобы еще ускорить алгоритм, необходимо упаковать несколько чисел в один контейнер, чтобы затем за константное количество шагов произвести хеширование для всех чисел, хранимых в контейнере. Для этого используется хеш-функция для хеширования <tex dpi="130">n</tex> чисел в таблицу размера <tex dpi="130">O(n^2)</tex> за константное время без коллизий. Для этого используется модифицированная хеш-функция авторства: Dierzfelbinger и Raman.
 
 
Алгоритм: Пусть целое число <tex dpi="130">b \geqslant 0</tex> и пусть <tex dpi="130">U = \{0, \ldots, 2^b - 1\}</tex>. Класс <tex dpi="130">H_{b,s}</tex> хеш-функций из <tex dpi="130">U</tex> в <tex dpi="130">\{0, \ldots, 2^s - 1\}</tex> определен как <tex dpi="130">H_{b,s} = \{h_{a} \mid 0 < a < 2^b, a \equiv 1 (\bmod 2)\}</tex> и для всех <tex dpi="130">x</tex> из <tex dpi="130">U</tex>: <tex dpi="130">h_{a}(x) = (ax</tex> <tex dpi="130">\bmod</tex> <tex dpi="130">2^b)</tex> <tex dpi="130">div</tex> <tex dpi="130">2^{b - s}</tex>.
 
Данный алгоритм базируется на [[#lemma1|лемме №1]].
 
 
Взяв <tex dpi="130">s = 2 \log n</tex>, получаем хеш-функцию <tex dpi="130">h_{a}</tex>, которая захеширует <tex dpi="130">n</tex> чисел из <tex dpi="130">U</tex> в таблицу размера <tex dpi="130">O(n^2)</tex> без коллизий. Очевидно, что <tex dpi="130">h_{a}(x)</tex> может быть посчитана для любого <tex dpi="130">x</tex> за константное время. Если упаковать несколько чисел в один контейнер так, что они разделены несколькими битами нулей, то можно применить <tex dpi="130">h_{a}</tex> ко всему контейнеру, и в результате все хеш-значения для всех чисел в контейнере будут посчитаны. Заметим, что это возможно только потому, что в вычисление хеш-значения вовлечены только (<tex dpi="130">\bmod</tex> <tex dpi="130">2^b</tex>) и (<tex dpi="130">div</tex> <tex dpi="130">2^{b - s}</tex>).
 
 
Такая хеш-функция может быть найдена за <tex dpi="130">O(n^3)</tex>.
 
Следует отметить, что, несмотря на размер таблицы <tex dpi="130">O(n^2)</tex>, потребность в памяти не превышает <tex dpi="130">O(n)</tex>, потому что хеширование используется только для уменьшения количества бит в числе.
 
==Сортировка по ключу==
Предположим, что <tex dpi="130">n</tex> чисел должны быть отсортированы, и в каждом <tex dpi="130">\log m</tex> бит. Будем считать, что в каждом числе есть <tex dpi="130">h</tex> сегментов, в каждом из которых <tex dpi="130">\log</tex> <tex dpi="150">\frac{m}{h}</tex> бит. Теперь применяем хеширование ко всем сегментам и получаем <tex dpi="130">2h \log n</tex> бит хешированных значений для каждого числа. После сортировки на хешированных значениях для всех начальных чисел начальная задача по сортировке <tex dpi="130">n</tex> чисел по <tex dpi="130">\log m</tex> бит в каждом стала задачей по сортировке <tex dpi="130">n</tex> чисел по <tex dpi="130">\log</tex> <tex dpi="150">\frac{m}{h}</tex> бит в каждом.
 
 
Также рассмотрим проблему последующего разделения. Пусть <tex dpi="130">a_{1}</tex>, <tex dpi="130">a_{2}</tex>, <tex dpi="130">\ldots</tex>, <tex dpi="130">a_{p}</tex> {{---}} <tex dpi="130">p</tex> чисел и <tex dpi="130">S</tex> {{---}} множество чисeл. Необходимо разделить <tex dpi="130">S</tex> в <tex dpi="130">p + 1</tex> наборов, таких, что: <tex dpi="130">S_{0} < a_{1} < S_{1} < a_{2} < \ldots < a_{p} < S_{p}</tex>. Так как используется '''сортировка по ключу''' (англ. ''signature sorting'') то перед тем, как делать вышеописанное разделение, необходимо поделить биты в <tex dpi="130">a_{i}</tex> на <tex dpi="130">h</tex> сегментов и взять некоторые из них. Так же делим биты для каждого числа из <tex dpi="130">S</tex> и оставляем только один в каждом числе. По существу, для каждого <tex dpi="130">a_{i}</tex> берутся все <tex dpi="130">h</tex> сегментов. Если соответствующие сегменты <tex dpi="130">a_{i}</tex> и <tex dpi="130">a_{j}</tex> совпадают, то нам понадобится только один. Сегмент, который берется для числа в <tex dpi="130">S</tex> это сегмент, который выделяется из <tex dpi="130">a_{i}</tex>. Таким образом, начальная задача о разделении <tex dpi="130">n</tex> чисел по <tex dpi="130">\log m</tex> бит преобразуется в несколько задач на разделение с числами по <tex dpi="150">\frac{\log m}{h}</tex> бит.
 
 
'''Пример''':
[[Файл:Han-example.png|500px|thumb]]
 
<tex dpi="130">a_{1} = 3, a_{2} = 5, a_{3} = 7, a_{4} = 10, S = \{1, 4, 6, 8, 9, 13, 14\}</tex>.
 
Делим числа на два сегмента. Для <tex dpi="130">a_{1}</tex> получим верхний сегмент <tex dpi="130">0</tex>, нижний <tex dpi="130">3</tex>; <tex dpi="130">a_{2}</tex> {{---}} верхний <tex dpi="130">1</tex>, нижний <tex dpi="130">1</tex>; <tex dpi="130">a_{3}</tex> {{---}} верхний <tex dpi="130">1</tex>, нижний <tex dpi="130">3</tex>; <tex dpi="130">a_{4}</tex> {{---}} верхний <tex dpi="130">2</tex>, нижний <tex dpi="130">2</tex>. Для элементов из S получим: для <tex dpi="130">1</tex> нижний <tex dpi="130">1</tex>, так как он выделяется из нижнего сегмента <tex dpi="130">a_{1}</tex>; для <tex dpi="130">4</tex> нижний <tex dpi="130">0</tex>; для <tex dpi="130">8</tex> нижний <tex dpi="130">0</tex>; для <tex dpi="130">9</tex> нижний <tex dpi="130">1</tex>; для <tex dpi="130">13</tex> верхний <tex dpi="130">3</tex>; для <tex dpi="130">14</tex> верхний <tex dpi="130">3</tex>. Теперь все верхние сегменты, нижние сегменты <tex dpi="130">1</tex> и <tex dpi="130">3</tex>, нижние сегменты <tex dpi="130">4, 5, 6, 7,</tex> нижние сегменты <tex dpi="130">8, 9, 10</tex> формируют <tex dpi="130">4</tex> новые задачи на разделение.
 
 
 
Использование '''сортировки по ключу''' в данном алгоритме:
 
Есть набор <tex dpi="130">T</tex> из <tex dpi="130">p</tex> чисел, которые отсортированы как <tex dpi="130">a_{1}, a_{2}, \ldots, a_{p}</tex>. Используем числа в <tex dpi="130">T</tex> для разделения набора <tex dpi="130">S</tex> из <tex dpi="130">q</tex> чисел <tex dpi="130">b_{1}, b_{2}, \ldots, b_{q}</tex> в <tex dpi="130">p + 1</tex> наборов <tex dpi="130">S_{0}, S_{1}, \ldots, S_{p}</tex>. Пусть <tex dpi="150">h = \frac{\log n}{c \log p}</tex> для константы <tex dpi="130">c > 1</tex>. (<tex dpi="150">\frac{h}{\log\log n \log p}</tex>)-битные числа могут храниться в одном контейнере, содержащим <tex dpi="150">\frac{\log n}{c \log\log n}</tex> бит. Сначала рассматриваем биты в каждом <tex dpi="130">a_{i}</tex> и каждом <tex dpi="130">b_{i}</tex> как сегменты одинаковой длины <tex dpi="150">\frac{h} {\log\log n}</tex>. Рассматриваем сегменты как числа. Чтобы получить неконсервативное преимущество для сортировки, числа в этих контейнерах (<tex dpi="130">a_{i}</tex>-ом и <tex dpi="130">b_{i}</tex>-ом) хешируются, и получается <tex dpi="150">\frac{h}{\log\log n}</tex> хешированных значений в одном контейнере. При вычислении хеш-значений сегменты не влияют друг на друга, можно даже отделить четные и нечетные сегменты в два контейнера. Не умаляя общности считаем, что хеш-значения считаются за константное время. Затем, посчитав значения, два контейнера объединяем в один. Пусть <tex dpi="130">a'_{i}</tex> {{---}} хеш-контейнер для <tex dpi="130">a_{i}</tex>, аналогично <tex dpi="130">b'_{i}</tex>. В сумме хеш-значения имеют <tex dpi="150">\frac{2 \log n}{c \log\log n}</tex> бит, хотя эти значения разделены на сегменты по <tex dpi="150">\frac{h}{ \log\log n}</tex> бит в каждом контейнере. Между сегментами получаются пустоты, которые забиваются нулями. Сначала упаковываются все сегменты в <tex dpi="150">\frac{2 \log n}{c \log\log n}</tex> бит. Потом рассматривается каждый хеш-контейнер как число, и эти хеш-контейнеры сортируются за линейное время (сортировка будет рассмотрена чуть позже). После этой сортировки биты в <tex dpi="130">a_{i}</tex> и <tex dpi="130">b_{i}</tex> разрезаны на <tex dpi="150">\frac{\log\log n}{h}</tex> сегментов. Таким образом, получилось дополнительное мультипликативное преимущество (англ. ''additional multiplicative advantage'') в <tex dpi="150">\frac{h} {\log\log n}</tex>.
 
После того, как вышеописанный процесс повторится <tex dpi="130">g</tex> раз, получится неконсервативное преимущество в <tex dpi="150">(\frac{h} {\log\log n})^g</tex> раз, в то время как потрачено только <tex dpi="130">O(gqt)</tex> времени, так как каждое многократное деление происходит за линейное время <tex dpi="130">O(qt)</tex>.
 
 
Хеш-функция, которая используется, находится следующим образом. Будут хешироватся сегменты, <tex dpi="150">\frac{\log\log n}{h}</tex>-ые, <tex dpi="150">(\frac{\log\log n}{h})^2</tex>-ые, <tex dpi="130">\ldots</tex> по счету в числе. Хеш-функцию для <tex dpi="150">(\frac{\log\log n}{h})^t</tex>-ых по счету сегментов, получаем нарезанием всех <tex dpi="130">p</tex> чисел на <tex dpi="150">(\frac{\log\log n}{h})^t</tex> сегментов. Рассматривая каждый сегмент как число, получаем <tex dpi="150">p(\frac{\log\log n}{h})^t</tex> чисел. Затем получаем одну хеш-функцию для этих чисел. Так как <tex dpi="130">t < \log n</tex>, то получится не более <tex dpi="130">\log n</tex> хеш-функций.
 
 
Рассмотрим сортировку за линейное время, о которой было упомянуто ранее. Предполагается, что хешированные значения для каждого контейнера упакованы в <tex dpi="150">\frac{2 \log n}{c \log\log n}</tex> бит. Есть <tex dpi="130">t</tex> наборов, в каждом из которых <tex dpi="130">q + p</tex> хешированных контейнеров по <tex dpi="150">\frac{2 \log n}{c \log\log n}</tex> бит в каждом. Эти контейнеры должны быть отсортированы в каждом наборе. Комбинируя все хеш-контейнеры в один pool, сортируем следующим образом.
 
 
Операция '''сортировки за линейное время''' (англ. ''Linear-Time-Sort'')
 
Входные данные: <tex dpi="150">r \geqslant n^{\frac{2}{5}}</tex> чисел <tex dpi="130">d_{i}</tex>, <tex dpi="130">d_{i}.value</tex> — значение числа <tex dpi="130">d_{i}</tex>, в котором <tex dpi="150">\frac{2 \log n}{c \log\log n}</tex> бит, <tex dpi="130">d_{i}.set</tex> — набор, в котором находится <tex dpi="130">d_{i}</tex>. Следует отметить, что всего есть <tex dpi="130">t</tex> наборов.
 
# Сортируем все <tex dpi="130">d_{i}</tex> по <tex dpi="130">d_{i}.value</tex>, используя bucket sort. Пусть все отсортированные числа в <tex dpi="130">A[1..r]</tex>. Этот шаг занимает линейное время, так как сортируется не менее <tex dpi="150">n^{\frac{2}{5}}</tex> чисел.
# Помещаем все <tex dpi="130">A[j]</tex> в <tex dpi="130">A[j].set</tex>.
 
==Сортировка с использованием O(n log log n) времени и памяти==
Для сортировки <tex dpi="130">n</tex> целых чисел в диапазоне <tex dpi="130">\{0, 1, \ldots, m - 1\}</tex> предполагается, что в нашем консервативном алгоритме используется контейнер длины <tex dpi="130">O(\log (m + n))</tex>. Далее везде считается, что все числа упакованы в контейнеры одинаковой длины.
 
 
Берем <tex dpi="130">1/e = 5</tex> для ЭП-дерева Андерссона. Следовательно, у корня будет <tex dpi="150">n^{\frac{1}{5}}</tex> детей, и каждое ЭП-дерево в каждом ребенке будет иметь <tex dpi="150">n^{\frac{4}{5}}</tex> листьев. В отличие от оригинального дерева, за раз вставляется не один элемент, а <tex dpi="130">d^2</tex>, где <tex dpi="130">d</tex> — количество детей узла дерева, в котором числа должны спуститься вниз. Алгоритм полностью опускает все <tex dpi="130">d^2</tex> чисел на один уровень. В корне опускаются <tex dpi="150">n^{\frac{2}{5}}</tex> чисел на следующий уровень. После того, как все числа опустились на следующий уровень, они успешно разделились на <tex dpi="130">t_{1} = n^{1/5}</tex> наборов <tex dpi="130">S_{1}, S_{2}, \ldots, S_{t_{1}}</tex>, в каждом из которых <tex dpi="150">n^{\frac{4}{5}}</tex> чисел и <tex dpi="130">S_{i} < S_{j}, i < j</tex>. Затем, берутся <tex dpi="150">n^{\frac{8}{25}}</tex> чисел из <tex dpi="130">S_{i}</tex> и опускаются на следующий уровень ЭП-дерева. Это повторяется, пока все числа не опустятся на следующий уровень. На этом шаге числа разделены на <tex dpi="150">t_{2} = n^{\frac{1}{5}}n^{\frac{4}{25}} = n^{\frac{9}{25}}</tex> наборов <tex dpi="130">T_{1}, T_{2}, \ldots, T_{t_{2}}</tex>, аналогичных наборам <tex dpi="130">S_{i}</tex>, в каждом из которых <tex dpi="150">n^{\frac{16}{25}}</tex> чисел. Теперь числа опускаются дальше в ЭП-дереве.
 
Нетрудно заметить, что перебалансирока занимает <tex dpi="130">O(n \log\log n)</tex> времени с <tex dpi="130">O(n)</tex> времени на уровень, аналогично стандартному ЭП-дереву Андерссона.
 
 
Нам следует нумеровать уровни ЭП-дерева с корня, начиная с нуля. Рассмотрим спуск вниз на уровне <tex dpi="130">s</tex>. Имеется <tex dpi="150">t = n^{1 - (\frac{4}{5})^S}</tex> наборов по <tex dpi="150">n^{(\frac{4}{5})^S}</tex> чисел в каждом. Так как каждый узел на данном уровне имеет <tex dpi="150">p = n^{\frac{1}{5} \cdot (\frac{4}{5})^S}</tex> детей, то на <tex dpi="130">s + 1</tex> уровень опускаются <tex dpi="150">q = n^{\frac{2}{5} \cdot (\frac{4}{5})^S}</tex> чисел для каждого набора, или всего <tex dpi="150">qt \geqslant n^{\frac{2}{5}}</tex> чисел для всех наборов за один раз.
 
 
Спуск вниз можно рассматривать как сортировку <tex dpi="130">q</tex> чисел в каждом наборе вместе с <tex dpi="130">p</tex> числами <tex dpi="130">a_{1}, a_{2}, \ldots, a_{p}</tex> из ЭП-дерева, так, что эти <tex dpi="130">q</tex> чисел разделены в <tex dpi="130">p + 1</tex> наборов <tex dpi="130">S_{0}, S_{1}, \ldots, S_{p}</tex> таких, что <tex dpi="130">S_{0} < a_{1} < \ldots < a_{p} < S_{p}</tex>.
 
 
Так как <tex dpi="130">q</tex> чисел не надо полностью сортировать и <tex dpi="130">q = p^2</tex>, то можно использовать [[#lemma6|лемму №6]] для сортировки. Для этого необходимо неконсервативное преимущество, которое получается с помощью [[Сортировка Хана#Signature sorting|signature sorting]]. Для этого используется линейная техника многократного деления (англ. ''multi-dividing technique'').
начало
Поместить После <texdpi="130">a_g</tex> сокращений бит в [[Сортировка Хана#Signature sorting|signature sorting]] получаем неконсервативное преимущество в <tex dpi="150">(\frac{ih}{ \log\log n})^g</tex> в соответствующий набор . Мы не волнуемся об этих сокращениях до конца потому, что после получения неконсервативного преимущества мы можем переключиться на [[#lemma6|лемму №6]] для завершения разделения <tex dpi="130">q</tex> чисел с помощью bucket sort потому<tex dpi="130">p</tex> чисел на наборы. Заметим, что наборов около по природе битового сокращения начальная задача разделения для каждого набора перешла в <tex dpi="130">w</tex> подзадач разделения на <texdpi="130">\sqrt{n}w</tex> поднаборов для какого-то числа <tex dpi="130">w</tex>.
Для каждого набора <tex>S = </tex>{<tex>a_{i_{0}}, a_{i_{1}}, ..., a_{i_{t}}</tex>}, если <tex>t > sqrt{n}</tex>, вызвать Sort(<tex>kloglogn</tex>, <tex>log_{k}((logn)/4)</tex>, <tex>a_{i_{0}}, a_{i_{1}}, ..., a_{i_{t}}</tex>)
конецТеперь для каждого набора все его поднаборы в подзадачах собираются в один набор. Затем, используя [[#lemma6|лемму №6]], делается разделение. Так как получено неконсервативное преимущество в <tex dpi="150">(\frac{h}{\log\log n})^g</tex> и работа происходит на уровнях не ниже, чем <tex dpi="130">2 \log\log\log n</tex>, то алгоритм занимает <tex dpi="150">O(\frac{qt \log\log n}{g(\log h - \log\log\log n) - \log\log\log n}) = O(\log\log n)</tex> времени.
Время работы алгоритма <tex>O(nloglogn/logk)</tex>, что доказывает лемму 2.
В итоге разделились <tex dpi="130">q</tex> чисел <tex dpi=Собственно сортировка с использованием O(nloglogn) времени и памяти"130">p</tex> числами в каждый набор. То есть получилось, что <tex dpi="130">S_{0} < e_{1} < S_{1} < \ldots < e_{p} < S_{p}</tex>, где <tex dpi=Для сортировки "130">e_{i}</tex>n{{---}} сегмент </texdpi="130"> целых чисел в диапазоне от a_{i}</tex>0, 1, полученный с помощью битового сокращения.Такое разделение получилось комбинированием всех поднаборов в подзадачах..Предполагаем, что числа хранятся в массиве <tex dpi="130">B</tex> так, m что числа в <tex dpi="130">S_{i}</tex> предшествуют числам в <tex dpi="130">S_{j}</tex> если <tex dpi="130">i < j</tex> и <tex dpi="130">e_{i}</tex> хранится после <tex dpi="130">S_{i - 1}</tex>} мы предполагаем, что используем контейнер длины но до <texdpi="130">O(log(m + n))S_{i}</tex> в нашем консервативном алгоритме. Мы всегда считаем что все числа упакованы в контейнеры одинаковой длины.
Берем <tex>1/e = 5</tex> для экспоненциального поискового дереве Андерссона. Поэтому у корня будет <tex>n^{1/5}</tex> детей и каждое Э.П.дерево в каждом ребенке будет иметь <tex>n^{4/5}</tex> листьев. В отличии от оригинального дерева, мы будем вставлять не один элемент за раз а <tex>d^2</tex>, где <tex>d</tex> {{---}} количество детей узла дерева, где числа должны спуститься вниз.
Но мы не будем сразу опускать донизу все <tex>d^2</tex> чисел. Мы будем полностью опускать все <tex>d^2</tex> чисел на один уровень. В корне мы опустим <tex>n^{2/5}</tex> чисел на следующий уровень. После того, как мы опустили все числа на следующий уровень мы успешно разделили числа на <tex>t_{1} = n^{1/5}</tex> наборов <tex>S_{1}, S_{2}, ..., S_{t_{1}}</tex>, в каждом из которых <tex>n^{4/5}</tex> чисел и <tex>S_{i} < S_{j}, i < j</tex>. Затем мы берем <tex>n^{(4/5)(2/5)}</tex> чисел из <tex>S_{i}</tex> за раз и опускаем их на следующий уровень Э.П.дерева. Повторяем это, пока все числа не опустятся на следующий уровень. На этом шаге мы разделили числа на <tex>t_{2} = n^{1/5}n^{4/25} = n^{9/25}</tex> наборов <tex>T_{1}, T_{2}, ..., T_{t_{2}}</tex> в каждом из которых <tex>n^{16/25}</tex> чисел, аналогичным наборам <tex>S_{i}</tex>. Теперь мы можем дальше опустить числа в нашем Э.П.дереве.
Нетрудно заметить, что ребалансирока занимает Пусть <texdpi="130">O(nloglogn)B[i]</tex> времени с находится в поднаборе <texdpi="130">O(n)B[i].subset</tex> временем на уровень. Аналогично стандартному ЭЧтобы позволить разделению выполниться, для каждого поднабора помещаем все <tex dpi="130">B[j]</tex> в <tex dpi="130">B[j].П.дереву Андерссонаsubset</tex>.
Нам следует нумеровать уровни Э.П.дерева с корня, начиная с нуля. Рассмотрим спуск вниз на уровне <tex>s</tex>. Мы имеем <tex>t = n^{1 - (4/5)^s}</tex> наборов по <tex>n^{(4/5)^s}</tex> чисел в каждом. Так как каждый узел на данном уровне имеет <tex>p = n^{(1/5)(4/5)^s}</tex> детей, то на <tex>s + 1</tex> уровень мы опустим <tex>q = n^{(2/5)(4/5)^s}</tex> чисел для каждого набора или всего <tex>qt >= n^{2/5}</tex> чисел для всех наборов за один разНа это потребуется линейное время и место.
Спуск вниз можно рассматривать как сортировку <tex>q</tex> чисел в каждом наборе вместе с <tex>p</tex> числами <tex>a_{1}, a_{2}, ..., a_{p}</tex> из Э.П.дерева, так, что эти <tex>q</tex> чисел разделены в <tex>p + 1</tex> наборов <tex>S_{0}, S_{1}, ..., S_{p}</tex> таких, что <tex>S_{0} < </tex>{<tex>a_{1}</tex>} < ... < {<tex>a_{p}</tex>}<tex> < S_{p}</tex>.
Так Теперь рассмотрим проблему упаковки, которая решается следующим образом. Считается, что число бит в контейнере <tex dpi="130">\log m \geqslant \log\log\log n</tex>, потому что в противном случае можно использовать radix sort для сортировки чисел. У контейнера есть <tex dpi="150">\frac{h}{\log\log n}</tex> хешированных значений (сегментов) в себе на уровне <tex dpi="130">\log h</tex> в ЭП-дереве. Полное число хешированных бит в контейнере равно <tex dpi="130">(2 \log n)(c \log\log n)</tex> бит. Хешированные биты в контейнере выглядят как нам не надо полностью сортировать <texdpi="130">q0^{i}t_{1}0^{i}t_{2} \ldots t</tex> чисел <tex dpi="150">_{\frac{h}{\log\log n}}</tex>, где <tex dpi="130">t_{k}</tex>-ые — хешированные биты, а нули {{---}} это просто нули. Сначала упаковываем <tex dpi="130">\log\log n</tex> контейнеров в один и получаем <texdpi="130">q w_{1} = p0^{j}t_{1, 1}t_{2, 1} \ldots t_{\log\log n, 1}0^{j}t_{1, 2} \ldots t_{\log\log n,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex>, есть возможность использовать лемму где <tex dpi="130">t_{i, k}</tex>: элемент с номером <tex dpi="130">k = 1, 2 для сортировки, \ldots, </tex><tex dpi="150">\frac{h}{\log\log n}</tex> из <tex dpi="130">i</tex>-ого контейнера. Для этого нам надо неконсервативное преимущество которое мы получим нижеИспользуем <tex dpi="130">O(\log\log n)</tex> шагов, чтобы упаковать <tex dpi="130">w_{1}</tex> в <tex dpi="130">w_{2} = 0</tex><tex dpi="150">^{\frac{jh}{\log\log n}}</tex><tex dpi="130">t_{1, 1}t_{2, 1} \ldots t_{\log\log n, 1}t_{1, 2}t_{2, 2} \ldots t_{1,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex><tex dpi="130">t_{2,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex><tex dpi="130">\ldots t_{\log\log n,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex>. Для этого используем линейную технику многократного деления Теперь упакованные хеш-биты занимают <tex dpi="130">2 \log</tex><tex dpi="150">\frac{n}{c}</tex> бит. Используем <tex dpi="130">O(multi-dividing technique\log\log n) </tex> времени чтобы добиться этогораспаковать <tex dpi="130">w_{2}</tex> в <tex dpi="130">\log\log n</tex> контейнеров <tex dpi="130">w_{3, k} = 0</tex><tex dpi="150">^{\frac{jh}{\log\log n}}</tex><tex dpi="130">0^{r}t_{k, 1}0^{r}t_{k, 2} \ldots t_{k,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex> <tex dpi="130">k = 1, 2, \ldots, \log\log n</tex>. Затем, используя <tex dpi="130">O(\log\log n)</tex> времени, упаковываем эти <tex dpi="130">\log\log n</tex> контейнеров в один <tex dpi="130">w_{4} = 0^{r}t_{1, 1}0^{r}t_{1, 2} \ldots t_{1,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex><tex dpi="130">0^{r}t_{2, 1} \ldots t_{\log\log n,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex>. Затем, используя <tex dpi="130">O(\log\log n)</tex> шагов, упаковываем <tex dpi="130">w_{4}</tex> в <tex dpi="130">w_{5} = 0^{s}t_{1, 1}t_{1, 2} \ldots t_{1,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex><tex dpi="130">t_{2, 1}t_{2, 2} \ldots t_{\log\log n,}</tex><tex dpi="150">_{ \frac{h}{\log\log n}}</tex>. В итоге используется <tex dpi="130">O(\log\log n)</tex> времени для упаковки <tex dpi="130">\log\log n</tex> контейнеров. Считаем, что время, потраченное на один контейнер — константа.
Для этого воспользуемся signature sorting==См. Адаптируем этот алгоритм для нас. Предположим у нас есть набор <tex>T</tex> из <tex>p</tex> чисел, которые уже отсортированы как <tex>a_{1}, a_{2}, ..., a_{p}</tex>, и мы хотим использовать числа в <tex>T</tex> для разделения <tex>S</tex> из <tex>q</tex> чисел <tex>b_{1}, b_{2}, ..., b_{q}</tex> в <tex>p + 1</tex> наборов <tex>S_{0}, S_{1}, ..., S_{p}</tex> что <tex>S_{0}</tex> < {<tex>a_{1}</tex>} < <tex>S_{1}</tex> < ... < {<tex>a_{p}</tex>} < <tex>S_{p}</tex>. Назовем это разделением <tex>q</tex> чисел <tex>p</tex> числами. Пусть <tex>h также== logn/(clogp)</tex> для константы <tex>c > 1</tex>. <tex>h/loglognlogp</tex> битные числа могут быть хранены в одном контейнере, так что одно слово хранит <tex>(logn)/(cloglogn)</tex> бит. Сначала рассматриваем биты в каждом <tex>a_{i}</tex> и каждом <tex>b_{i}</tex> как сегменты одинаковой длины <tex>h/loglogn</tex>. Рассматриваем сегменты как числа. Чтобы получить неконсервативное преимущество для сортировки мы хэштруем числа в этих контейнерах (<tex>a_{i}</tex>-ом и <tex>b_{i}</tex>-ом) чтобы получить <tex>h/loglogn</tex> хэшированных значений в одном контейнере. Чтобы получить значения сразу, при вычислении хэш значений сегменты не влияют друг на друга, мы можем даже отделить четные и нечетные сегменты в два контейнера. Не умаляя общности считаем, что хэш значения считаются за константное время. Затем, посчитав значения мы объединяем два контейнера в один. Пусть <tex>a'_{i}</tex> хэш контейнер для <tex>a_{i}</tex>, аналогично <tex>b'_{i}</tex>. В сумме хэш значения имеют <tex>(2logn)/(cloglogn)</tex> бит. Хотя эти значения разделены на сегменты по <tex>h/loglogn</tex> бит в каждом контейнере. Сначала упаковываем все сегменты в <tex>(2logn)/(cloglogn)</tex> бит. Потом рассмотрим каждый хэш контейнер как число и отсортируем эти хэш слова за линейное время (* [[Сортировка подсчетом]]* [[Цифровая сортировка рассмотрена чуть позже). После этой сортировки биты в <tex>a_{i}</tex> и <tex>b_{i}</tex> разрезаны на <tex>loglogn/h</tex>. Таким образом мы получили дополнительное мультипликативное преимущество в <tex>h/loglogn</tex> (additional multiplicative advantage).]]
После того, как мы повторили вышеописанный процесс <tex>g<==Источники информации==* [http://www.sciencedirect.com/science/tex> раз мы получили неконсервативное преимущество в <tex>(harticle/loglogn)^g<pii/tex> раз, в то время как мы потратили только <tex>S019667740300155X Deterministic Sorting in O(gqtn log log n)</tex> времени, так как каждое многократное деление делятся за линейное время <tex>OTime and Linear Space. Yijie Han.]* А. Андерссон. Fast deterministic sorting and searching in linear space. Proc. 1996 IEEE Symp. on Foundations of Computer Science. 135-141(qt1996)<* [http://dl.acm.org/tex>citation.cfm?id=1236460 A. Andersson, M. Thorup. Dynamic ordered sets with exponential search trees.]* [[wikipedia:en:Integer_sorting|Wikipedia {{---}} Integer sorting]]
Хэш функция, которую мы используем, находится следующим образом. Мы будем хэшировать сегменты, которые <tex>loglogn/h</tex>-ые, <tex>(loglogn/h)^2</tex>-ые, ... от всего числа. Для сегментов вида <tex>(loglogn/h)^t</tex>, получаем нарезанием всех <tex>p</tex> чисел на <tex>(loglogn/h)^t</tex> сегментов. Рассматривая каждый сегмент как число мы получаем <tex>p(loglogn/h)^t</tex> чисел. Затем получаем одну хэш функцию для этих чисел. Так как <tex>t < logn</tex> то мы получим не более <tex>logn</tex> хэш функций.[[Категория: Дискретная математика и алгоритмы]]
Рассмотрим сортировку за линейное время о которой было упомянуто ранее.[[Категория: Сортировка]]
25
правок

Навигация