Задача сортировки. Классификация и свойства сортировок

Модуль "Сортировки" • урок 1 из 17 •

Суть урока. Сортировка - упорядочивание по ключу; нужна как предобработка (чтобы работал бинарный поиск O(log N)). Классификация: внутренние (в ОЗУ) / внешние (на диске); устойчивые (сохраняют порядок равных) / нет; простые O(N²) (вставкой, выборкой, пузырьковая) и эффективные O(N log N) (Шелла, пирамидальная, Хоара). Нижняя граница сортировки сравнениями - O(N log N).

Задача сортировки. Что это такое и зачем нужно?

Сортировка - это алгоритмический процесс упорядочивания (перестановки) элементов множества по определенному критерию (ключу сортировки) по возрастанию или убыванию. Это одна из самых исследованных и фундаментальных задач информатики.

Сортировка редко является самоцелью. Чаще всего это важнейший этап предобработки данных. Как мы разбирали в предыдущем модуле, быстрый дихотомический (бинарный) поиск за логарифмическое время O(log N) возможен только в отсортированных массивах. Кроме того, сортировка нужна для группировки данных, быстрого устранения дубликатов и подготовки отчетов.

Классификация алгоритмов сортировки

За десятилетия развития информатики было придумано огромное количество алгоритмов сортировки. Чтобы в них ориентироваться, их классифицируют по пяти основным признакам:

1. По месту хранения данных: Внутренние и Внешние

Задача сортировки
Классификация алгоритмов по месту хранения данных: Внутренние и Внешние

2. По вычислительной сложности: Простые и Эффективные

Простые и эффективные сортировки
Классификация алгоритмов по вычислительной сложности: Простые и Эффективные

3. По типу базовой операции: Сравнениями и Распределяющие

Сортировки сравнениями и распределяющие
Классификация алгоритмов по типу базовой операции: Сравнениями и Распределяющие

4. По использованию памяти: На месте и С дополнительной памятью

Сортировки на месте и с дополнительной памятью
Классификация алгоритмов по использованию памяти: На месте и С дополнительной памятью

5. По устойчивости

Устойчивая (стабильная) сортировка не меняет первоначальный относительный порядок элементов с одинаковыми ключами (сохранение первоначального относительного порядка одинаковых ключей гарантируется).

Представьте, что у вас есть список сотрудников, который уже отсортирован по фамилии по алфавиту. Теперь вы сортируете этот список по номеру отдела. Если алгоритм устойчивый, то внутри каждого отдела сотрудники останутся отсортированными по фамилии относительно друг друга (порядок сохраняется). Если алгоритм неустойчивый (применяются неустойчивые сортировки), алфавитный порядок внутри отделов нарушается и будет потерян (элементы меняются местами).

Устойчивость сортировки
Классификация алгоритмов по устойчивости: Устойчивые и Неустойчивые
А как в реальных языках программирования?
Создатели стандартных библиотек вынуждены искать компромисс между скоростью, расходом памяти и устойчивостью. Поэтому подходы к сортировке по умолчанию отличаются:
  • Неустойчивые (C и C++): Стандартные функции, такие как qsort (C) и std::sort (C++), исторически опираются на быструю сортировку Хоара (Quick Sort) или ее гибриды. Они сортируют данные прямо "на месте" без выделения дополнительной памяти и работают очень быстро, но жертвуют устойчивостью.
  • Устойчивые (Python и Java): Современные языки высокого уровня, такие как Python (функция sorted()) и Java, используют алгоритм Timsort. Он требует O(N) дополнительной памяти, зато строго устойчив и на частично отсортированных данных работает почти за линейное время O(N). Для случаев, когда стабильность критична, в C++ предусмотрена отдельная функция std::stable_sort.

Базовый инструментарий (на C)

Любой алгоритм внутренней сортировки на Си строится вокруг двух простейших операций: Сравнение (if a[i] > a[j]) и Обмен (Swap). Функцию обмена мы будем использовать во всех алгоритмах курса:

#include <stdio.h>

// Универсальная функция обмена двух переменных (Swap)
void Swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// Заглушка абстрактного алгоритма сортировки массива
void Sort(int arr[], int n) {
    // В следующих уроках мы будем заполнять эту функцию 
    // различными алгоритмами: от O(N^2) до O(N log N)
}

Коротко: главное

  • Зачем нужно: Предобработка данных для алгоритмов бинарного поиска O(log N).
  • Сложность: Простые алгоритмы работают за O(N²), эффективные за O(N log N).
  • Устойчивость: Важнейшее свойство алгоритма, сохраняющее первоначальный относительный порядок равных по ключу элементов.

Проверьте себя

Что означает свойство "устойчивости" алгоритма сортировки?

Как вам урок? Спасибо за отзыв!