Какие алгоритмы используются в С++ 11 std:: sort в разных реализациях STL?

Стандарт С++ 11 гарантирует, что std::sort имеет O (n logn) сложность в худшем случае. Это отличается от гарантии среднего размера в С++ 98/03, где std::sort может быть реализована с помощью Quicksort (возможно, в сочетании с сортировкой вставки для небольшого n), которая имеет O (n ^ 2) в худшем случае (для некоторого конкретного ввода, такого как отсортированный вход).

Были ли какие-либо изменения в реализациях std::sort в разных библиотеках STL? Как реализован С++ 11 std::sort в разных STL?

Ответ 1

Просмотр онлайн-источников для libstdС++ и libС++, можно видеть, что обе библиотеки используют полную гамму известных алгоритмов сортировки из основного цикла intro-sort:

Для std::sort существует вспомогательная подпрограмма для алгоритма insertion_sort (an O(N^2), но с хорошей константой масштабирования, чтобы сделать ее конкурентоспособной для небольших последовательностей), плюс некоторый специальный корпус для подпоследовательностей 0, 1, 2 и 3 элемента.

Для std::partial_sort обе библиотеки используют версию heap_sort (O(N log N) в целом), потому что этот метод имеет хороший инвариант, что он сохраняет отсортированную подпоследовательность (обычно он имеет большую константу масштабирования, чтобы сделать его более дорогой для полной сортировки).

Для std::nth_element существует вспомогательная подпрограмма для selection_sort (опять-таки алгоритм O (N ^ 2) с хорошей константой склеивания, чтобы сделать его конкурентоспособным для небольших последовательностей). Для регулярной сортировки insertion_sort обычно доминирует selection_sort, но для nth_element инвариант наименьших элементов отлично соответствует поведению selection_sort.

Ответ 2

Вопрос в том, как STL скажет std::sort худший случай O (N log (N)), хотя он по сути является QuickSort. Сорт STL IntroSort. IntroSort - это, по сути, QuickSort, различие, введенное, изменяет сложность худшего случая.


Худший случай QuickSort - O (N ^ 2)

Что бы вы ни выбрали для разбиения на разделы, существует последовательность, которую QuickSort будет выполнять на O (N ^ 2). Выбранное разбиение уменьшает вероятность наихудшего случая. (Случайный выбор поворота, медианный из трех, и т.д.)

EDIT: Благодаря коррекции @maxim1000 s. Быстрая сортировка с алгоритмом выбора опорных точек Медиана медианов имеет O (N log (N)) худшую сложность, но из-за накладных расходов она вводит ее не используется на практике. Он показывает, как хороший алгоритм выбора, может изменить сложность наихудшего случая посредством выбора поворота, теоретически.


Что делает IntroSort?

IntroSort ограничивает ветвление QuickSort. Это самый важный момент, этот предел 2 * (log N). Когда предел достигнут, IntroSort может использовать любой алгоритм сортировки, который имеет худшую сложность O (N log (N)).

Ветвление останавливается, когда у нас есть O (log N) подзадачи. Мы можем решить каждую подзадачу O (n log n). (Нижний регистр n обозначает размеры подзадач).

Сумма (n log n) - наша самая сложная проблема.

В худшем случае QuickSort; предположим, что у нас уже отсортированный массив, и мы всегда выбираем первый элемент в этом массиве как опорный элемент. На каждой итерации мы избавляемся от первого элемента. Если бы мы шли до конца, это было бы O (N ^ 2). В IntroSort мы останавливаем QuickSort, когда мы достигаем глубины log (N), тогда мы используем HeapSort для оставшегося несортированного массива.

16 -> 1  /**N**/
   \
    > 15 -> 1 /**N - 1**/
         \
          > 14 -> 1 /**N - 2**/
               \
                > 13 -> 1 /**N - log(N)**/  
                     \
                      > 12 /**(HeapSort Now) (N - log(N)) log (N - log(N))**/

Подведите итог,

Пока не прекратится ветвление, выполняются операции N + (N - 1) + ... + (N - log(N)). Вместо того, чтобы использовать gauss для подведения итогов, мы можем просто сказать N + (N - 1) + ... + (N - log(N)) < N log(N).

Часть HeapSort (N - log(N)) log(N - log(N)) < N log(N)

Общая сложность < 2 N log(N).

Поскольку константы могут быть опущены, худшая сложность IntroSort - O (N log (N)).


Добавлена ​​информация: GCC Исходный код STL-реализации здесь. Sort функция находится в строке 5461.

Исправление: * Microsoft.NET * sort Реализация IntroSort с 2012 года. Сопутствующая информация здесь.