Сортировка Хана — различия между версиями
Da1s60 (обсуждение | вклад) |
Da1s60 (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | '''Сортировка Хана (Yijie Han)''' {{---}} сложный алгоритм сортировки целых чисел со сложностью <tex>O( | + | '''Сортировка Хана (Yijie Han)''' {{---}} сложный алгоритм сортировки целых чисел со сложностью <tex>O(nloglog n)</tex>, где <tex>n</tex> {{---}} количество элементов для сортировки. |
Данная статья писалась на основе брошюры Хана, посвященной этой сортировке. Изложение материала в данной статье идет примерно в том же порядке, в каком она предоставлена в работе Хана. | Данная статья писалась на основе брошюры Хана, посвященной этой сортировке. Изложение материала в данной статье идет примерно в том же порядке, в каком она предоставлена в работе Хана. | ||
Строка 18: | Строка 18: | ||
|id=def2. | |id=def2. | ||
|definition= | |definition= | ||
− | Алгоритм сортирующий <tex>n</tex> целых чисел из множества <tex>\{0, 1, \ldots, m - 1\}</tex> называется консервативным, если длина контейнера (число бит в контейнере), является <tex>O(\log(m + n))</tex>. Если длина больше, то алгоритм | + | Алгоритм сортирующий <tex>n</tex> целых чисел из множества <tex>\{0, 1, \ldots, m - 1\}</tex> называется консервативным, если длина контейнера (число бит в контейнере), является <tex>O(\log(m + n))</tex>. Если длина больше, то алгоритм неконсервативный. |
}} | }} | ||
{{Определение | {{Определение | ||
|id=def3. | |id=def3. | ||
|definition= | |definition= | ||
− | Если мы сортируем целые числа из множества {0, 1, ..., <tex>m</tex> - 1} с длиной контейнера <tex>klog(m + n)</tex> с <tex>k</tex> >= 1, тогда мы сортируем с | + | Если мы сортируем целые числа из множества {0, 1, ..., <tex>m</tex> - 1} с длиной контейнера <tex>klog(m + n)</tex> с <tex>k</tex> >= 1, тогда мы сортируем с неконсервативным преимуществом <tex>k</tex>. |
}} | }} | ||
{{Определение | {{Определение | ||
Строка 70: | Строка 70: | ||
|id=lemma2. | |id=lemma2. | ||
|statement= | |statement= | ||
− | <tex>n</tex> целых чисел можно отсортировать в <tex>\sqrt{n}</tex> наборов <tex>S_{1}</tex>, <tex>S_{2}</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( | + | <tex>n</tex> целых чисел можно отсортировать в <tex>\sqrt{n}</tex> наборов <tex>S_{1}</tex>, <tex>S_{2}</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(nloglogn/logk)</tex> и место <tex>O(n)</tex> с не консервативным преимуществом <tex>kloglogn</tex> |
|proof= | |proof= | ||
+ | Доказательство данной леммы будет приведено далее в тексте статьи. | ||
}} | }} | ||
{{Лемма | {{Лемма | ||
Строка 90: | Строка 91: | ||
}} | }} | ||
− | Заметим, что когда <tex>g = O(logn)</tex> мы сортируем <tex>O(n)</tex> чисел в <tex>n/g</tex> контейнеров за время <tex>O((n/g) | + | Заметим, что когда <tex>g = O(logn)</tex> мы сортируем <tex>O(n)</tex> чисел в <tex>n/g</tex> контейнеров за время <tex>O((n/g)loglogn)</tex>, с использованием O(n/g) места. Выгода очевидна. |
{{Лемма | {{Лемма | ||
|id=lemma5. | |id=lemma5. | ||
|statement= | |statement= | ||
− | Если принять, что каждый контейнер содержит <tex>logm > logn</tex> бит, и <tex>g</tex> чисел, в каждом из которых <tex>(logm)/g</tex> бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий <tex>(logn)/(2g)</tex> бит, и <tex>g</tex> маркеров упакованы в один контейнер таким же образом<tex>^*</tex>, что и числа, тогда <tex>n</tex> чисел в <tex>n/g</tex> контейнерах могут быть отсортированы по их маркерам за время <tex>O(( | + | Если принять, что каждый контейнер содержит <tex>logm > logn</tex> бит, и <tex>g</tex> чисел, в каждом из которых <tex>(logm)/g</tex> бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий <tex>(logn)/(2g)</tex> бит, и <tex>g</tex> маркеров упакованы в один контейнер таким же образом<tex>^*</tex>, что и числа, тогда <tex>n</tex> чисел в <tex>n/g</tex> контейнерах могут быть отсортированы по их маркерам за время <tex>O((nloglogn)/g)</tex> с использованием <tex>O(n/g)</tex> места. |
(*): если число <tex>a</tex> упаковано как <tex>s</tex>-ое число в <tex>t</tex>-ом контейнере для чисел, тогда маркер для <tex>a</tex> упакован как <tex>s</tex>-ый маркер в <tex>t</tex>-ом контейнере для маркеров. | (*): если число <tex>a</tex> упаковано как <tex>s</tex>-ое число в <tex>t</tex>-ом контейнере для чисел, тогда маркер для <tex>a</tex> упакован как <tex>s</tex>-ый маркер в <tex>t</tex>-ом контейнере для маркеров. | ||
|proof= | |proof= | ||
Строка 112: | Строка 113: | ||
Заметим, что если длина контейнера <tex>logmloglogn</tex> и только <tex>logm</tex> бит используется для упаковки <tex>g <= logn</tex> чисел в один контейнер, тогда выбор в лемме три может быть сделан за время и место <tex>O(n/g)</tex>, потому, что упаковка в доказатльстве леммы три теперь может быть сделана за время <tex>O(n/g)</tex>. | Заметим, что если длина контейнера <tex>logmloglogn</tex> и только <tex>logm</tex> бит используется для упаковки <tex>g <= logn</tex> чисел в один контейнер, тогда выбор в лемме три может быть сделан за время и место <tex>O(n/g)</tex>, потому, что упаковка в доказатльстве леммы три теперь может быть сделана за время <tex>O(n/g)</tex>. | ||
+ | |||
+ | ==Сортировка <tex>n</tex> целых чисел в <tex>\sqrt{n}</tex> наборов== | ||
+ | Постановка задачи и решение некоторых проблем: | ||
+ | |||
+ | Рассмотрим проблему сортировки <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>-уровневый алгоритм, который работает следующим образом: |
Версия 01:36, 12 июня 2012
Сортировка Хана (Yijie Han) — сложный алгоритм сортировки целых чисел со сложностью
, где — количество элементов для сортировки.Данная статья писалась на основе брошюры Хана, посвященной этой сортировке. Изложение материала в данной статье идет примерно в том же порядке, в каком она предоставлена в работе Хана.
Содержание
Алгоритм
Алгоритм построен на основе экспоненциального поискового дерева (далее — Э.П.дерево) Андерсона (Andersson's exponential search tree). Сортировка происходит за счет вставки целых чисел в Э.П.дерево.
Andersson's exponential search tree
Э.П.дерево с
листьями состоит из корня и (0< <1) Э.П.поддеревьев, в каждом из которых листьев; каждое Э.П.поддерево является сыном корня . В этом дереве уровней. При нарушении баланса дерева, необходимо балансирование, которое требует времени при вставленных целых числах. Такое время достигается за счет вставки чисел группами, а не по одиночке, как изначально предлагает Андерссон.Необходимая информация
Определение: |
Контейнер — объект определенного типа, содержащий обрабатываемый элемент. Например __int32, __int64, и т.д. |
Определение: |
Алгоритм сортирующий | целых чисел из множества называется консервативным, если длина контейнера (число бит в контейнере), является . Если длина больше, то алгоритм неконсервативный.
Определение: |
Если мы сортируем целые числа из множества {0, 1, ..., | - 1} с длиной контейнера с >= 1, тогда мы сортируем с неконсервативным преимуществом .
Определение: |
Для множества min( Набор ) = min( : принадлежит ) max( ) = max( : принадлежит ) < если max( ) <= min( ) | определим
Уменьшение числа бит в числах
Один из способов ускорить сортировку — уменьшить число бит в числе. Один из способов уменьшить число бит в числе — использовать деление пополам (эту идею впервые подал van Emde Boas). Деление пополам заключается в том, что количество оставшихся бит в числе уменьшается в 2 раза. Это быстрый способ, требующий
памяти. Для своего дерева Андерссон использует хеширование, что позволяет сократить количество памяти до . Для того, чтобы еще ускорить алгоритм нам необходимо упаковать несколько чисел в один контейнер, чтобы затем за константное количество шагов произвести хэширование для всех чисел хранимых в контейнере. Для этого используется хэш функция для хэширования чисел в таблицу размера за константное время, без коллизий. Для этого используется хэш модифицированная функция авторства: Dierzfelbinger и Raman.Алгоритм: Пусть целое число
и пусть . Класс хэш функций из в определен как и для всех из .Данный алгоритм базируется на следующей лемме:
Лемма: |
Даны целые числа >= >= 0 и является подмножеством {0, ..., - 1}, содержащим элементов, и >= С . Функция принадлежащая может быть выбрана за время так, что количество коллизий |
Взяв
мы получим хэш функцию которая захэширует чисел из в таблицу размера без коллизий. Очевидно, что может быть посчитана для любого за константное время. Если мы упакуем несколько чисел в один контейнер так, что они разделены несколькими битами нулей, мы спокойно сможем применить ко всему контейнеру, а в результате все хэш значения для всех чисел в контейере были посчитаны. Заметим, что это возможно только потому, что в вычисление хэш знчения вовлечены только (mod ) и (div ).Такая хэш функция может быть найдена за
.Следует отметить, что несмотря на размер таблицы
, потребность в памяти не превышает потому, что хэширование используется только для уменьшения количества бит в числе.Signature sorting
В данной сортировке используется следующий алгоритм:
Предположим, что
чисел должны быть сортированы, и в каждом бит. Мы рассматриваем, что в каждом числе есть сегментов, в каждом из которых бит. Теперь мы применяем хэширование ко всем сегментам и получаем бит хэшированных значений для каждого числа. После сортировки на хэшированных значениях для всех начальных чисел начальная задача по сортировке чисел по бит в каждом стала задачей по сортировке чисел по бит в каждом.Так же, рассмотрим проблему последующего разделения. Пусть
, , ..., — чисел и — множество чисeл. Мы хотим разделить в наборов таких, что: < { } < < { } < ... < { } < . Т.к. мы используем signature sorting, до того как делать вышеописанное разделение, мы поделим биты в на сегментов и возьмем некоторые из них. Мы так же поделим биты для каждого числа из и оставим только один в каждом числе. По существу для каждого мы возьмем все сегментов. Если соответствующие сегменты и совпадают, то нам понадобится только один. Сегменты, которые мы берем для числа в , — сегмент, который выделяется из . Таким образом мы преобразуем начальную задачу о разделении чисел в бит в несколько задач на разделение с числами в бит.Пример:
= 3, = 5, = 7, = 10, S = {1, 4, 6, 8, 9, 13, 14}.
Мы разделим числа на 2 сегмента. Для
получим верхний сегмент 0, нижний 3; верхний 1, нижний 1; верхний 1, нижний 3; верхний 2, нижний 2. Для элементов из S получим: для 1: нижний 1 т.к. он выделяется из нижнего сегмента ; для 4 нижний 0; для 8 нижний 0; для 9 нижний 1; для 13 верхний 3; для 14 верхний 3. Теперь все верхние сегменты, нижние сегменты 1 и 3, нижние сегменты 4, 5, 6, 7, нижние сегменты 8, 9, 10 формируют 4 новые задачи на разделение.Сортировка на маленьких целых
Для лучшего понимания действия алгоритма и материала, изложенного в данной статье, в целом, ниже представлены несколько полезных лемм.
Лемма: |
целых чисел можно отсортировать в наборов , , ..., таким образом, что в каждом наборе чисел и < при < , за время и место с не консервативным преимуществом |
Доказательство: |
Доказательство данной леммы будет приведено далее в тексте статьи. |
Лемма: |
Выбор -ого наибольшего числа среди чисел упакованных в контейнеров может быть сделана за время и с использованием места. Конкретно медиана может быть так найдена. |
Доказательство: |
Так как мы можем делать попарное сравнение | чисел в одном контейнере с числами в другом и извлекать большие числа из одного контейнера и меньшие из другого за константное время, мы можем упаковать медианы из первого, второго, ..., -ого чисел из 5 контейнеров в один контейнер за константное время. Таким образом набор из медиан теперь содержится в контейнерах. Рекурсивно находим медиану в . Используя уберем хотя бы чисел среди . Затем упакуем оставшиеся из контейнеров в контейнеров и затем продолжим рекурсию.
Лемма: |
Если целых чисел, в сумме использующие бит, упакованы в один контейнер, тогда чисел в контейнерах могут быть отсортированы за время , с использованием места. |
Доказательство: |
Так как используется только Для контейнеров вне групп (которых бит в каждом контейнере для хранения чисел, мы можем использовать bucket sorting чтобы отсортировать все контейнеры. представляя каждый как число, что занимает времени и места. Потому, что мы используем бит на контейнер нам понадобится шаблонов для всех контейнеров. Затем поместим контейнеров с одинаковым шаблоном в одну группу. Для каждого шаблона останется не более контейнеров которые не смогут образовать группу. Поэтому не более контейнеров не смогут сформировать группу. Для каждой группы мы помещаем -е число во всех контейнерах в один. Таким образом мы берем -целых векторов и получаем -целых векторов где -ый вектор содержит -ое число из входящего вектора. Эта транспозиция может быть сделана за время , с использованием места. Для всех групп это занимает время , с использованием места. штук) мы просто разберем и соберем заново контейнеры. На это потребуется не более места и времени. После всего этого мы используем bucket sorting вновь для сортировки контейнеров. таким образом мы отсортируем все числа. |
Заметим, что когда
мы сортируем чисел в контейнеров за время , с использованием O(n/g) места. Выгода очевидна.Лемма: |
Если принять, что каждый контейнер содержит бит, и чисел, в каждом из которых бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий бит, и маркеров упакованы в один контейнер таким же образом , что и числа, тогда чисел в контейнерах могут быть отсортированы по их маркерам за время с использованием места.
(*): если число упаковано как -ое число в -ом контейнере для чисел, тогда маркер для упакован как -ый маркер в -ом контейнере для маркеров. |
Доказательство: |
Контейнеры для маркеров могут быть отсортированы с помощью bucket sort потому, что каждый контейнер использует | бит. Сортировка сгруппирует контейнеры для чисел как в четвертой лемме. Мы можем переместить каждую группу контейнеров для чисел.
Заметим, что сортирующие алгоритмы в четвертой и пятой леммах нестабильные. Хотя на их основе можно построить стабильные алгоритмы используя известный метод добавления адресных битов к каждому входящему числу.
Если у нас длина контейнеров больше, сортировка может быть ускорена, как показано в следующей лемме.
Лемма: |
предположим, что каждый контейнер содержит бит, что чисел, в каждом из которых бит, упакованы в один контейнер, что каждое число имеет маркер, содержащий бит, и что маркеров упакованы в один контейнер тем же образом что и числа, тогда чисел в контейнерах могут быть отсортированы по своим маркерам за время , с использованием памяти. |
Доказательство: |
Заметим, что несмотря на то, что длина контейнера | бит всего бит используется для хранения упакованных чисел. Так же как в леммах четыре и пять мы сортируем контейнеры упакованных маркеров с помощью bucket sort. Для того, чтобы перемещать контейнеры чисел мы помещаем вместо контейнеров чисел в одну группу. Для транспозиции чисел в группе содержащей контейнеров мы сначала упаковываем контейнеров в контейнеров упаковывая контейнеров в один. Далее мы делаем транспозицию над контейнерами. Таким образом перемещение занимает всего времени для каждой группы и времени для всех чисел. После завершения транспозиции, мы далее распаковываем контейнеров в контейнеров.
Заметим, что если длина контейнера
и только бит используется для упаковки чисел в один контейнер, тогда выбор в лемме три может быть сделан за время и место , потому, что упаковка в доказатльстве леммы три теперь может быть сделана за время .Сортировка целых чисел в наборов
Постановка задачи и решение некоторых проблем:
Рассмотрим проблему сортировки
целых чисел из множества {0, 1, ..., - 1} в наборов как во второй лемме. Мы предполагаем, что в каждом контейнере бит и хранит число в бит. Поэтому неконсервативное преимущество . Мы так же предполагаем, что . Иначе мы можем использовать radix sort для сортировки за время и линейную память. Мы делим бит, используемых для представления каждого числа, в блоков. Таким образом каждый блок содержит как минимум бит. -ый блок содержит с -ого по -ый биты. Биты считаются с наименьшего бита начиная с нуля. Теперь у нас имеется -уровневый алгоритм, который работает следующим образом: