Сортировка отбором (selection sort)
'Очевидный' алгоритм сортировки - перебором находится наименьший элемент, он
меняется местами с элементом, стоящим на нулевом месте, затем находится наименьший
среди оставшихся и меняется местами с элементом, стоящим на первом месте... Цикл
заканчивается когда будут выбраны все элементы:
Сортировка вставками (insertion sort)
Сортируемый масив просматривается в порядке возрастания номеров и каждый элемент
вставляется в уже просмотренную часть массива так, чтобы сохранить порядок. На
каждом шаге сортировки часть массива уже упорядочена, поэтому для поиска места
вставки можно использовать метод половинного деления:
Пузырьковая сортировка (bubble sort)
Наверное, самый короткий алгоритм сортировки, но и один из самых медленных:
Сортировка слиянием (merge sort)
'Divide-and-conquer' - 'разделяй и властвуй' - исходный массив делится
пополам, каждая половинка упорядочивается, затем производится слияние. Для
сортировки половинок используется та же функция, что и для сортировки всего
массива, функция слияния выделена для экономии места в стеке:
Сходная идея используется в алгоритме распределения/слияния:
Сортировка с помощью кучи (heap sort)
Этот алгоритм почти также эффективен, как сортировка слиянием и он не
требует дополнительной памяти. Но вот назвать его очевидным вряд ли можно...
Алгоритм основан на том, что сортируемому массиву может быть поставлено в соответствие двоичное дерево, каждый узел которого соответствует одному элементу массива с некоторым номером k и этот узел содержит ссылки на два других узла, соответствующих элементам с номерами 2*k+1 и 2*k+2. Корень дерева соответствует элементу с номером 0 (ноль).
Так определенная структура действительно является двоичным деревом и все элементы массива входят в него. Предположим, что это не так и некоторому элементу m не соответствует никакой узел дерева. Тогда и элементу n=(m-1)/2 не соответствует никакой узел дерева (иначе приходим к противоречию, т.к. m=2*n+1 или m=2*n+2). Продолжая рассуждение придем к тому, что элемент с номером 0 (т.е. корень дерева) не входит дерево, опять противоречие.
Далее, допустим, что на некоторый элемент k имеются ссылки из узлов с различными номерами p и q (без ограничения общности q>p, т.е. q=p+r, r>=1):
Противоречие доказывает, что построенная структура является двоичным деревом.
Дальнейшие действия следующие - массив переупорядочивается так, чтобы для любого k выполнялись неравенства:
Затем массив еще раз переупорядочивается, уже по возрастанию номеров. Каждый из этих шагов требует ~N*log(N) операций. 'Очевидная' реализация может быть такой:
Быстрая сортировка (quick sort)
Алгоритм основан на разделениии сортируемого массива на части и перестановке элементов
таким образом, чтобы элементы в левой части массива не превосходили элементов в правой.
На каждом шаге выбирается 'средний' элемент массива, в результате ряда перестановок он
занимает свое свое законное место, затем каждая из частей упорядочивается:
В более сложных реализациях алгоритма 'средний' элемент выбирается как средний из трех или случайным образом. Но как минимум, необходимо заменить один из рекурсивных вызовов циклом, это предотвратит разрушение стека:
Сортировка подсчетом (counting sort)
Неуниверсальный алгоритм, использующий дополнительную память и выполняющий
сортировку за время, пропорциональное числу элементов массива. Для его
реализации необходимо взаимно однозначно сопоставить каждому возможному
значению элемента массива целое неотрицательное число и нужно, чтобы
максимальное из этих чисел не превосходило значительно числа элементов
массива. Тогда имеет смысл следующий алгоритм:
Алгоритм может быть использован и в случае, когда ширина диапазона значений элементов массива значительно превосходит число элементов. Очевидно, любой ключ представляется послебовательностью байт. Можно разделить ключ на группы и последовательно упрорядочить массив по каждой из групп. Время сортировки в этом случае пропорционально произведению числа элементов на число групп. Например, если дан массив строк, каждая строка может быть разбита на группы по два символа. Максимальное значение ключа в группе не превосходит 65535 (2**16-1).
Алгоритм эффективен только для очень больших массивов.