Как устроена функция sort в C++ STL?

Ответ

std::sort из заголовка <algorithm> — это гибридный алгоритм сортировки, который в большинстве реализаций (например, в libstdc++ и libc++) представляет собой Introsort.

Как работает Introsort:

  1. Начинается как быстрая сортировка (Quicksort) с медианой из трёх для выбора опорного элемента.
  2. Отслеживает глубину рекурсии. Если она превышает 2 * log₂(n), алгоритм переключается на пирамидальную сортировку (Heapsort). Это гарантирует сложность O(n log n) в худшем случае и предотвращает деградацию до O(n²) на специально подобранных данных.
  3. Для маленьких подмассивов (обычно размером менее 16-32 элементов) часто применяется сортировка вставками (Insertion Sort) из-за её эффективности на небольших наборах.

Синтаксис и использование:

#include <algorithm>
#include <vector>
#include <functional>

std::vector<int> data = {5, 1, 4, 2, 8};

// 1. Сортировка по возрастанию (использует operator<)
std::sort(data.begin(), data.end());

// 2. Сортировка по убыванию с использованием функционального объекта
std::sort(data.begin(), data.end(), std::greater<int>());

// 3. Сортировка с пользовательским компаратором (лямбда)
std::sort(data.begin(), data.end(), [](int a, int b) {
    return (a % 3) < (b % 3); // Сортировка по остатку от деления на 3
});

Ключевые особенности std::sort:

  • Требует итераторов произвольного доступа: Работает с std::vector, std::deque, std::array и обычными массивами. Не работает с std::list (для него есть метод list::sort()).
  • Нестабильная: Не сохраняет относительный порядок равных элементов. Для стабильной сортировки используйте std::stable_sort.
  • Компаратор: Должен обеспечивать строгое слабое упорядочение. Например, для сортировки по убыванию корректно использовать std::greater<>(), а не [](int a, int b) { return a > b; } (хотя лямбда также допустима).

Ответ 18+ 🔞

А, ну это же классика, ёпта! std::sort — это не просто какая-то там сортировка, это, блядь, целый гибридный зверь под капотом, который в большинстве библиотек зовётся Introsort. И он не дурак, работает с умом.

Как этот хитрожопый Introsort выкручивается:

  1. Стартует он как быстрая сортировка (Quicksort), да ещё и с умным выбором опорного элемента — медианой из трёх. Не какой-нибудь случайный хуй с горы берёт.
  2. Но тут главный фокус: он, сука, глубину рекурсии считает. Если чувствует, что закапывается слишком глубоко (больше 2 * log₂(n)), то у него терпения ебать ноль, и он резко переключается на пирамидальную сортировку (Heapsort). Это гениально, потому что худший случай становится O(n log n), и никакие специально подогнанные данные его не взломают. На этом многие наивные реализации быстрой сортировки накрываются медным тазом, а наш — нет.
  3. А для совсем мелких подмассивов (ну там, меньше 16 элементов) он вообще не парится и врубает сортировку вставками (Insertion Sort), потому что на мелочи она — просто ядрёна вошь, быстрее всех.

Как этим пользоваться, чтобы не выглядеть мудем:

#include <algorithm>
#include <vector>
#include <functional>

std::vector<int> data = {5, 1, 4, 2, 8};

// 1. Просто сортировка по возрастанию (использует operator<)
std::sort(data.begin(), data.end()); // Всё, готово.

// 2. Хочешь по убыванию — вот тебе готовый функциональный объект
std::sort(data.begin(), data.end(), std::greater<int>());

// 3. Ну а если надо какую-то свою, ебанутую логику — лямбда в руки
std::sort(data.begin(), data.end(), [](int a, int b) {
    return (a % 3) < (b % 3); // Сортировка по остатку от деления на 3, например. Ну а хули?
});

Важные фишки, которые надо помнить, чувак:

  • Ест только итераторы произвольного доступа: То есть std::vector, std::deque, std::array и голые массивы — пожалуйста. А вот std::list сюда не суй — у него свой метод list::sort() есть, распиздяй.
  • Нестабильный, блядь: Равные элементы могут перепутаться. Если для тебя это как вилкой в глаз, бери std::stable_sort.
  • С компаратором не обосрись: Он должен строгое слабое упорядочение обеспечивать. Для сортировки по убыванию проще и правильнее std::greater<>() взять, хотя и лямбда [](int a, int b) { return a > b; } сработает. Но ты чувствуешь подвох? Вот и я чувствую. Лучше не выёживайся без нужды.