<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://apmath.info/w/index.php?action=history&amp;feed=atom&amp;title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8</id>
	<title>Сортировки - История изменений</title>
	<link rel="self" type="application/atom+xml" href="https://apmath.info/w/index.php?action=history&amp;feed=atom&amp;title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8"/>
	<link rel="alternate" type="text/html" href="https://apmath.info/w/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;action=history"/>
	<updated>2026-11-03T19:45:22Z</updated>
	<subtitle>История изменений этой страницы в вики</subtitle>
	<generator>MediaWiki 1.36.2</generator>
	<entry>
		<id>https://apmath.info/w/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=285&amp;oldid=prev</id>
		<title>СВ: Новая страница: «== TL;DR ==  '''Сортировка''' — упорядочивание элементов по ключу. Все '''сравнительные''' сортир...»</title>
		<link rel="alternate" type="text/html" href="https://apmath.info/w/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8&amp;diff=285&amp;oldid=prev"/>
		<updated>2026-09-30T19:27:35Z</updated>

		<summary type="html">&lt;p&gt;Новая страница: «== TL;DR ==  &amp;#039;&amp;#039;&amp;#039;Сортировка&amp;#039;&amp;#039;&amp;#039; — упорядочивание элементов по ключу. Все &amp;#039;&amp;#039;&amp;#039;сравнительные&amp;#039;&amp;#039;&amp;#039; сортир...»&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;== TL;DR ==&lt;br /&gt;
&lt;br /&gt;
'''Сортировка''' — упорядочивание элементов по ключу. Все '''сравнительные''' сортировки (использующие только сравнения) подчиняются '''нижней границе &amp;lt;math&amp;gt;\Omega(n\log n)&amp;lt;/math&amp;gt;''': дерево решений содержит &amp;lt;math&amp;gt;n!&amp;lt;/math&amp;gt; исходов-перестановок, значит глубина &amp;lt;math&amp;gt;\ge \log_2(n!) = \Theta(n\log n)&amp;lt;/math&amp;gt;. Быстрее &amp;lt;math&amp;gt;n\log n&amp;lt;/math&amp;gt; удаётся только '''не-сравнительным''' сортировкам — '''подсчётом''' (&amp;lt;math&amp;gt;O(n+k)&amp;lt;/math&amp;gt;), '''поразрядно''' (&amp;lt;math&amp;gt;O(d(n+k))&amp;lt;/math&amp;gt;), '''карманной''' (среднее &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;) — за счёт использования структуры ключей. Внутри класса &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; выбор определяется свойствами: '''устойчивость''' (слияние, [[Timsort]]), '''память &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;''' ([[Пирамидальная сортировка]]), '''средняя скорость''' ([[Быстрая сортировка]], introsort). Эта статья — '''обзор'''; детали каждого алгоритма — в отдельных статьях: [[Быстрая сортировка]], [[Сортировка слиянием]], [[Пирамидальная сортировка]], [[Timsort]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Свойство !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Класс || Алгоритмы упорядочивания по ключу&lt;br /&gt;
|-&lt;br /&gt;
| Сравнительные || нижняя граница &amp;lt;math&amp;gt;\Omega(n\log n)&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Достижимо || &amp;lt;math&amp;gt;\Theta(n\log n)&amp;lt;/math&amp;gt; в худшем: слияние, heapsort, Timsort&lt;br /&gt;
|-&lt;br /&gt;
| Быстрее || только не-сравнительные: подсчёт, radix, bucket (&amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;/&amp;lt;math&amp;gt;O(n+k)&amp;lt;/math&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| Свойства || устойчивость, in-place, адаптивность, гарантия&lt;br /&gt;
|-&lt;br /&gt;
| Библиотеки || &amp;lt;code&amp;gt;std::sort&amp;lt;/code&amp;gt; (introsort), &amp;lt;code&amp;gt;std::stable_sort&amp;lt;/code&amp;gt;, Python/Java (Timsort)&lt;br /&gt;
|-&lt;br /&gt;
| Обозначения || &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; — число элементов, &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — диапазон ключей, &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; — число разрядов&lt;br /&gt;
|-&lt;br /&gt;
| Связанные || [[Асимптотическая сложность]], [[Амортизационный анализ]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Определения ==&lt;br /&gt;
&lt;br /&gt;
'''Задача сортировки.''' Дан массив &amp;lt;math&amp;gt;a[1..n]&amp;lt;/math&amp;gt; с ключами из линейно упорядоченного множества; требуется переставить элементы так, чтобы ключи не убывали: &amp;lt;math&amp;gt;a[1] \le a[2] \le \dots \le a[n]&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Сравнительная сортировка (comparison sort)''' — алгоритм, который получает информацию о ключах '''только через сравнения''' &amp;lt;math&amp;gt;a[i] \lessgtr a[j]&amp;lt;/math&amp;gt;. К этому классу относятся quicksort, mergesort, heapsort, insertion sort и др.&lt;br /&gt;
&lt;br /&gt;
'''Не-сравнительная сортировка''' — использует дополнительную структуру ключей (диапазон, разряды, распределение) и '''не считает сравнения''' как основную операцию: counting sort, radix sort, bucket sort.&lt;br /&gt;
&lt;br /&gt;
'''Устойчивость (stability)''' — равные ключи сохраняют исходный взаимный порядок.&lt;br /&gt;
&lt;br /&gt;
'''На месте (in-place)''' — алгоритм переставляет элементы в самом массиве, используя &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; (или &amp;lt;math&amp;gt;O(\log n)&amp;lt;/math&amp;gt; под рекурсию) памяти сверх входа.&lt;br /&gt;
&lt;br /&gt;
'''Адаптивность''' — алгоритм ускоряется, если вход уже частично упорядочен.&lt;br /&gt;
&lt;br /&gt;
'''Дерево решений (decision tree)''' — модель сравнительной сортировки: каждый внутренний узел — сравнение, каждый лист — результат (перестановка); высота дерева равна числу сравнений в худшем случае.&lt;br /&gt;
&lt;br /&gt;
'''Нижняя граница &amp;lt;math&amp;gt;\Omega(n\log n)&amp;lt;/math&amp;gt;.''' Любая сравнительная сортировка выполняет не менее &amp;lt;math&amp;gt;\lceil\log_2(n!)\rceil = \Theta(n\log n)&amp;lt;/math&amp;gt; сравнений в худшем случае.&lt;br /&gt;
&lt;br /&gt;
'''Обозначения.''' &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; — число элементов; &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число возможных значений ключа; &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; — число разрядов; &amp;lt;math&amp;gt;\log&amp;lt;/math&amp;gt; — двоичный.&lt;br /&gt;
&lt;br /&gt;
== Мотивация и интуиция ==&lt;br /&gt;
&lt;br /&gt;
Сортировка — базовая операция: она ускоряет поиск ([[Дерево Фенвика]], двоичный поиск), объединение (join в СУБД), отображение и дедупликацию. Вопрос «как быстро в принципе?» имеет точный ответ: сравнительные сортировки '''не могут''' быть быстрее &amp;lt;math&amp;gt;n\log n&amp;lt;/math&amp;gt;, и этот предел достигается (mergesort, heapsort). См. рис. 1 и рис. 2.&lt;br /&gt;
&lt;br /&gt;
[[Файл:so-01-overview.svg|frame|none|700px|Рис. 1. Два семейства: сравнительные (граница &amp;lt;math&amp;gt;n\log n&amp;lt;/math&amp;gt;) и не-сравнительные (используют структуру ключей).]]&lt;br /&gt;
&lt;br /&gt;
Ключевая идея нижней границы — '''подсчёт различимых исходов'''. Чтобы отсортировать &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; различных элементов, алгоритм должен уметь отличить любую из &amp;lt;math&amp;gt;n!&amp;lt;/math&amp;gt; перестановок. Каждое сравнение даёт один бит информации (две ветви), поэтому дерево решений глубины &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; имеет не более &amp;lt;math&amp;gt;2^d&amp;lt;/math&amp;gt; листьев. Отсюда &amp;lt;math&amp;gt;2^d \ge n!&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;d \ge \log_2(n!) = \Theta(n\log n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обойти границу можно, '''выйдя за модель сравнений''': если ключи — целые в диапазоне &amp;lt;math&amp;gt;0..k&amp;lt;/math&amp;gt;, можно посчитать их частоты и разложить элементы без сравнений (counting sort); если ключи — мультиразрядные, сортировать по разрядам (radix); если равномерны — раскладывать по карманам (bucket).&lt;br /&gt;
&lt;br /&gt;
[[Файл:so-02-decisiontree.svg|frame|none|700px|Рис. 2. Для &amp;lt;math&amp;gt;n = 3&amp;lt;/math&amp;gt;: 6 листьев-перестановок; отсюда &amp;lt;math&amp;gt;\ge \log_2 6 \approx 2.58&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;\ge 3&amp;lt;/math&amp;gt; сравнения.]]&lt;br /&gt;
&lt;br /&gt;
== Устройство ==&lt;br /&gt;
&lt;br /&gt;
Сравнительные сортировки делятся на три группы по времени (см. рис. 1):&lt;br /&gt;
&lt;br /&gt;
* '''&amp;lt;math&amp;gt;\Theta(n^2)&amp;lt;/math&amp;gt;''': вставками, выбором, пузырьком — простые, хороши на малых &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;;&lt;br /&gt;
* '''&amp;lt;math&amp;gt;\Theta(n\log n)&amp;lt;/math&amp;gt;''': слиянием (устойчива, &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; памяти), heapsort (&amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; памяти), Timsort (устойчива, адаптивна);&lt;br /&gt;
* '''быстрая''': &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; в среднем, &amp;lt;math&amp;gt;\Theta(n^2)&amp;lt;/math&amp;gt; в худшем (сводится к &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; в introsort).&lt;br /&gt;
&lt;br /&gt;
=== Нижняя граница: доказательство (см. рис. 3) ===&lt;br /&gt;
&lt;br /&gt;
'''Модель.''' Сортирующий алгоритм — это '''дерево решений''': в каждом узле — сравнение двух элементов, две ветви соответствуют исходам. Листья — возможные результаты.&lt;br /&gt;
&lt;br /&gt;
'''Доказательство.''' Для &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; различных ключей существует &amp;lt;math&amp;gt;n!&amp;lt;/math&amp;gt; перестановок, и алгоритм обязан различать их (разным входам, требующим разного порядка, соответствуют разные листья). Двоичное дерево высоты &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; имеет не более &amp;lt;math&amp;gt;2^d&amp;lt;/math&amp;gt; листьев, поэтому &amp;lt;math&amp;gt;2^d \ge n!&amp;lt;/math&amp;gt;, откуда &amp;lt;math&amp;gt;d \ge \log_2(n!)&amp;lt;/math&amp;gt;. По формуле Стирлинга &amp;lt;math&amp;gt;n! \approx \sqrt{2\pi n}(n/e)^n&amp;lt;/math&amp;gt;, значит &amp;lt;math&amp;gt;\log_2(n!) = n\log_2 n - 1.44n + O(\log n) = \Theta(n\log n)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;\square&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Следствие.''' Любой алгоритм из класса сравнений требует &amp;lt;math&amp;gt;\Omega(n\log n)&amp;lt;/math&amp;gt; сравнений в худшем случае; algorithms слияния и heapsort достигают этой границы по порядку.&lt;br /&gt;
&lt;br /&gt;
[[Файл:so-03-lowerbound.svg|frame|none|700px|Рис. 3. &amp;lt;math&amp;gt;\log_2(n!) = \Theta(n\log n)&amp;lt;/math&amp;gt;: верхняя и нижняя оценки зажимают границу.]]&lt;br /&gt;
&lt;br /&gt;
=== Как обойти границу (см. рис. 4) ===&lt;br /&gt;
&lt;br /&gt;
Отказавшись от сравнений, получаем линейные (по &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;) сортировки при подходящих ключах:&lt;br /&gt;
&lt;br /&gt;
* '''Counting sort:''' ключи &amp;lt;math&amp;gt;0..k&amp;lt;/math&amp;gt;; считаем частоты, строим префиксные суммы, раскладываем элементы на свои места. &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* '''Radix sort (LSD):''' сортируем устойчиво по младшему разряду, затем по следующему. &amp;lt;math&amp;gt;O(d(n+k))&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;d&amp;lt;/math&amp;gt; — число разрядов.&lt;br /&gt;
* '''Bucket sort:''' равномерные ключи на &amp;lt;math&amp;gt;[0,1)&amp;lt;/math&amp;gt;; раскладываем по карманам, каждый сортируем вставками. Среднее &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:so-04-noncomparison.svg|frame|none|700px|Рис. 4. Подсчётом, поразрядно и карманами — ценой предположений о ключах.]]&lt;br /&gt;
&lt;br /&gt;
'''Важно:''' эти сортировки не «нарушают» нижнюю границу — граница верна '''только для модели сравнений'''. Они получают информацию о ключах бесплатно (индексация, разряды), чего сравнительная модель не позволяет.&lt;br /&gt;
&lt;br /&gt;
== Операции и алгоритмы ==&lt;br /&gt;
&lt;br /&gt;
=== Группа: квадратичные сортировки ===&lt;br /&gt;
&lt;br /&gt;
'''Вставками.''' На каждом шаге вставляем &amp;lt;code&amp;gt;a[i]&amp;lt;/code&amp;gt; в отсортированный префикс, сдвигая большие элементы. &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; (в худшем), &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; на почти отсортированных; устойчива, in-place. Хороша на малых &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; и как «хвост» гибридов.&lt;br /&gt;
&lt;br /&gt;
'''Выбором.''' Находим минимум в остатке и ставим на место. &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;, мало обменов (&amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;), но '''неустойчива''' и не адаптивна.&lt;br /&gt;
&lt;br /&gt;
'''Пузырьком.''' Обмены соседних «неправильных» пар. &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;; учебный, на практике заменяется вставками.&lt;br /&gt;
&lt;br /&gt;
=== Группа: $O(n\log n)$ ===&lt;br /&gt;
&lt;br /&gt;
* '''Слиянием''' ([[Сортировка слиянием]]): деление пополам и устойчивое слияние; гарантия &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt;, память &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;; на списках — &amp;lt;math&amp;gt;O(\log n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* '''Пирамидальная''' ([[Пирамидальная сортировка]]): max-куча и извлечение максимума; &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; всегда при &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; памяти; неустойчива.&lt;br /&gt;
* '''Быстрая''' ([[Быстрая сортировка]]): разбиение вокруг опорного; &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; в среднем, &amp;lt;math&amp;gt;\Theta(n^2)&amp;lt;/math&amp;gt; в худшем; in-place, но неустойчива; introsort гарантирует &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* '''Timsort''' ([[Timsort]]): natural runs + слияние с инвариантом стека; лучший &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;, худший &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt;; устойчива и адаптивна.&lt;br /&gt;
&lt;br /&gt;
=== Группа: не-сравнительные ===&lt;br /&gt;
&lt;br /&gt;
'''Counting sort''' (см. рис. 4):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Алгоритм Counting-Sort(a, k)&lt;br /&gt;
Вход:  a[0..n−1], ключи — целые 0..k&lt;br /&gt;
Выход: a отсортирован (устойчиво)&lt;br /&gt;
Сложность: O(n + k) времени, O(n + k) памяти&lt;br /&gt;
&lt;br /&gt;
1  for v ← 0 to k: cnt[v] ← 0&lt;br /&gt;
2  for i ← 0 to n − 1: cnt[a[i]] ← cnt[a[i]] + 1&lt;br /&gt;
3  for v ← 1 to k: cnt[v] ← cnt[v] + cnt[v − 1]      # префиксные суммы&lt;br /&gt;
4  for i ← n − 1 downto 0                              # справа налево → устойчиво&lt;br /&gt;
5      cnt[a[i]] ← cnt[a[i]] − 1&lt;br /&gt;
6      out[cnt[a[i]]] ← a[i]&lt;br /&gt;
7  return out&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Radix sort (LSD):''' для каждого разряда (от младшего) выполнить устойчивую counting-сортировку по этому разряду. Корректность — индукция по разрядам: устойчивость сохраняет предыдущий порядок.&lt;br /&gt;
&lt;br /&gt;
'''Bucket sort:''' разложить по &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; карманам по значению ключа, отсортировать карманы вставками (средний размер &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; при равномерности), собрать. Среднее &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;, худший &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Сводная таблица сложности ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Алгоритм !! Средний !! Худший !! Память !! Устойчив !! In-place !! Адаптивен&lt;br /&gt;
|-&lt;br /&gt;
| Вставками || &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; || да || да || да (O(n))&lt;br /&gt;
|-&lt;br /&gt;
| Выбором || &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; || нет || да || нет&lt;br /&gt;
|-&lt;br /&gt;
| Слиянием || &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; || да || нет || слабо&lt;br /&gt;
|-&lt;br /&gt;
| Пирамидальная || &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; || нет || да || слабо&lt;br /&gt;
|-&lt;br /&gt;
| Быстрая || &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(\log n)&amp;lt;/math&amp;gt; || нет || да || слабо&lt;br /&gt;
|-&lt;br /&gt;
| Timsort || &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; || да || нет || да (O(n))&lt;br /&gt;
|-&lt;br /&gt;
| Подсчётом || &amp;lt;math&amp;gt;O(n+k)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n+k)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n+k)&amp;lt;/math&amp;gt; || да || нет || нет&lt;br /&gt;
|-&lt;br /&gt;
| Radix (LSD) || &amp;lt;math&amp;gt;O(d(n+k))&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(d(n+k))&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n+k)&amp;lt;/math&amp;gt; || да || нет || нет&lt;br /&gt;
|-&lt;br /&gt;
| Bucket || &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; || да* || нет || нет&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Оговорки: *bucket sort устойчив, если карманы сортируются устойчиво и собираются по порядку. Не-сравнительные сортировки требуют предположений о ключах. Полная таблица — на рис. 5.&lt;br /&gt;
&lt;br /&gt;
== Трассировка примера ==&lt;br /&gt;
&lt;br /&gt;
Замерим число '''сравнений''' на массиве из &amp;lt;math&amp;gt;n = 4096&amp;lt;/math&amp;gt; случайных чисел (прогон из «Служебного»):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Алгоритм !! Сравнений (≈) !! Отношение к &amp;lt;math&amp;gt;n\log_2 n&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Вставками || &amp;lt;math&amp;gt;\approx n^2/4&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;\approx 21.5&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Слиянием || &amp;lt;math&amp;gt;\approx 0.98\,n\log_2 n&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;\approx 1.0&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Пирамидальная || &amp;lt;math&amp;gt;\approx 1.9\,n\log_2 n&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;\approx 1.9&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Быстрая (медиана трёх) || &amp;lt;math&amp;gt;\approx 1.0\,n\log_2 n&amp;lt;/math&amp;gt; || &amp;lt;math&amp;gt;\approx 1.0&amp;lt;/math&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Подсчётом || &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; сравнений || —&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Все сравнительные не опускаются ниже &amp;lt;math&amp;gt;\log_2(n!) \approx n\log_2 n - 1.44n&amp;lt;/math&amp;gt; — нижняя граница выполняется. Counting sort делает '''ноль''' сравнений элементов (использует ключи как индексы). Трассировка сверена с реализацией из раздела «Служебное».&lt;br /&gt;
&lt;br /&gt;
== Корректность и оценка сложности ==&lt;br /&gt;
&lt;br /&gt;
=== Нижняя граница ===&lt;br /&gt;
&lt;br /&gt;
Доказана выше через дерево решений: &amp;lt;math&amp;gt;d \ge \log_2(n!) = \Theta(n\log n)&amp;lt;/math&amp;gt;. Более точная оценка с константами: &amp;lt;math&amp;gt;\log_2(n!) = n\log_2 n - 1.44n + O(\log n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Достижимость ===&lt;br /&gt;
&lt;br /&gt;
Сортировка слиянием делает &amp;lt;math&amp;gt;T(n) = 2T(n/2) + \Theta(n) = \Theta(n\log n)&amp;lt;/math&amp;gt; сравнений (см. [[Сортировка слиянием]]); heapsort — не более &amp;lt;math&amp;gt;2n\log_2 n&amp;lt;/math&amp;gt;; Timsort сохраняет &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt;. Значит, граница достижима по порядку, и класс &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; для сравнений '''оптимален'''.&lt;br /&gt;
&lt;br /&gt;
=== Корректность counting sort ===&lt;br /&gt;
&lt;br /&gt;
После шага 3 &amp;lt;code&amp;gt;cnt[v]&amp;lt;/code&amp;gt; — число элементов &amp;lt;math&amp;gt;\le v&amp;lt;/math&amp;gt;. Проход справа налево (шаг 4) кладёт элемент на позицию &amp;lt;code&amp;gt;cnt[a[i]] - 1&amp;lt;/code&amp;gt;, уменьшая счётчик: равные элементы идут в порядке справа налево, то есть '''устойчиво'''. После всех &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; шагов каждый элемент на своём месте. &amp;lt;math&amp;gt;\square&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Радикс ===&lt;br /&gt;
&lt;br /&gt;
Каждый разряд обрабатывается устойчивой counting-сортировкой; индукция по разрядам (LSD) гарантирует правильный порядок после старшего разряда.&lt;br /&gt;
&lt;br /&gt;
== Сравнение с альтернативами ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Критерий выбора !! Что брать&lt;br /&gt;
|-&lt;br /&gt;
| Нужна устойчивость || [[Сортировка слиянием]], [[Timsort]], вставками, подсчётом&lt;br /&gt;
|-&lt;br /&gt;
| Нужна память &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; || [[Пирамидальная сортировка]], вставками, [[Быстрая сортировка]]&lt;br /&gt;
|-&lt;br /&gt;
| Нужна максимальная средняя скорость || [[Быстрая сортировка]] / introsort&lt;br /&gt;
|-&lt;br /&gt;
| Нужна адаптивность || [[Timsort]]&lt;br /&gt;
|-&lt;br /&gt;
| Нужна гарантия &amp;lt;math&amp;gt;O(n\log n)&amp;lt;/math&amp;gt; || [[Сортировка слиянием]], [[Пирамидальная сортировка]], introsort&lt;br /&gt;
|-&lt;br /&gt;
| Целые ключи, малый диапазон || counting sort, radix&lt;br /&gt;
|-&lt;br /&gt;
| Равномерные ключи || bucket sort&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Файл:so-05-table.svg|frame|none|700px|Рис. 5. Полная таблица: время, память, устойчивость, применения.]]&lt;br /&gt;
&lt;br /&gt;
'''Независимые свойства.''' Устойчивость, in-place, адаптивность и гарантия не связаны: нельзя получить всё сразу. Например, mergesort устойчив и гарантирован, но платит &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; памяти; heapsort экономит память, но неустойчив.&lt;br /&gt;
&lt;br /&gt;
[[Файл:so-06-stability.svg|frame|none|700px|Рис. 6. Четыре независимых свойства и их комбинации.]]&lt;br /&gt;
&lt;br /&gt;
== Где применяется ==&lt;br /&gt;
&lt;br /&gt;
# '''Стандартные библиотеки.''' &amp;lt;code&amp;gt;std::sort&amp;lt;/code&amp;gt; (introsort — скорость и гарантия), &amp;lt;code&amp;gt;std::stable_sort&amp;lt;/code&amp;gt; (слияние/Timsort), Python &amp;lt;code&amp;gt;sorted&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;list.sort&amp;lt;/code&amp;gt; (Timsort), Java &amp;lt;code&amp;gt;Arrays.sort&amp;lt;/code&amp;gt; (introsort для примитивов, Timsort для объектов). Почему: разные требования к устойчивости и памяти [1][5].&lt;br /&gt;
&lt;br /&gt;
# '''Системы реального времени и embedded.''' heapsort (&amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; памяти, гарантия) или сортировка вставками на малых данных. Почему: нельзя допустить худшего &amp;lt;math&amp;gt;\Theta(n^2)&amp;lt;/math&amp;gt; и лишних буферов [2].&lt;br /&gt;
&lt;br /&gt;
# '''Большие данные и внешняя сортировка.''' Слияние и многопутевое слияние: данные на диске, важен последовательный доступ. Почему: слияние линейно и последовательно [2][3].&lt;br /&gt;
&lt;br /&gt;
# '''Целые/короткие фиксированные ключи.''' Counting и radix в гистограммах, кодировании, биоинформатике (сортировка последовательностей по суффиксам/префиксам). Почему: &amp;lt;math&amp;gt;O(n+k)&amp;lt;/math&amp;gt; быстрее сравнений [1][5].&lt;br /&gt;
&lt;br /&gt;
# '''СУБД и аналитика.''' Sort-merge join, агрегации, оконные функции опираются на устойчивую сортировку и внешнее слияние. Почему: устойчивость и предсказуемость [3].&lt;br /&gt;
&lt;br /&gt;
[[Файл:so-07-applications.svg|frame|none|700px|Рис. 7. Выбор диктуют устойчивость, память, гарантия и структура ключей.]]&lt;br /&gt;
&lt;br /&gt;
== Историческая справка ==&lt;br /&gt;
&lt;br /&gt;
Сортировки — старейшая область алгоритмов. '''Пузырьковая''' и '''вставочная''' известны с первых лет вычислений; '''Shellsort''' предложил '''Дональд Шелл''' в 1959 году (обобщение вставок с шагами). '''Быструю''' сортировку изобрёл '''Тони Хоар''' (1961–1962) [6]; '''пирамидальную''' — '''Дж. Уильямс''' (1964) с линейным build-heap '''Р. Флойда''' (1964) [7]; '''слияние''' восходит к '''Джону фон Нейману''' (1945). Не-сравнительные сортировки уходят корнями в '''перфокарточные машины Холлерита''' (radix-сортировка, конец XIX века) и counting sort [5].&lt;br /&gt;
&lt;br /&gt;
'''Нижняя граница &amp;lt;math&amp;gt;\Omega(n\log n)&amp;lt;/math&amp;gt;''' через деревья решений — классический результат информационной теории; подробное изложение — '''Кнут''', т. 3 [5], и '''CLRS''', гл. 8 (сортировка за линейное время и нижняя граница) [1].&lt;br /&gt;
&lt;br /&gt;
== Типичные ошибки и подводные камни ==&lt;br /&gt;
&lt;br /&gt;
* '''Ожидание линейного времени от сравнительных сортировок.''' Невозможно (нижняя граница); &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; достижим только вне модели сравнений.&lt;br /&gt;
* '''Применение counting/radix к произвольным ключам.''' Нужны целые/ограниченный диапазон; иначе &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; велик, и сортировка медленна.&lt;br /&gt;
* '''Неустойчивость там, где нужна устойчивость.''' Сортировка по составным ключам требует устойчивого алгоритма (mergesort/Timsort), а не quicksort/heapsort.&lt;br /&gt;
* '''Игнорирование памяти.''' mergesort/Timsort требуют &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;; в embedded берут heapsort.&lt;br /&gt;
* '''Худший случай quicksort.''' На «анти-входах» — &amp;lt;math&amp;gt;\Theta(n^2)&amp;lt;/math&amp;gt;; лечится рандомизацией/introsort.&lt;br /&gt;
* '''Переполнение ключей в counting.''' Диапазон &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; и счётчики должны помещаться в тип.&lt;br /&gt;
* '''Путаница &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;O(n+k)&amp;lt;/math&amp;gt;.''' Если &amp;lt;math&amp;gt;k \gg n&amp;lt;/math&amp;gt;, counting/radix проигрывают сравнениям.&lt;br /&gt;
* '''Смешение 0- и 1-базной индексации''' в counting (позиции &amp;lt;code&amp;gt;cnt[a[i]] - 1&amp;lt;/code&amp;gt;).&lt;br /&gt;
* '''Сортировка маленьких массивов «тяжёлым» алгоритмом.''' На &amp;lt;math&amp;gt;n &amp;lt; 16&amp;lt;/math&amp;gt; вставки быстрее; гибриды так и делают.&lt;br /&gt;
* '''Stable vs in-place trade-off.''' Нельзя одновременно иметь обе дешёвые; помните о компромиссе.&lt;br /&gt;
&lt;br /&gt;
== Задачи для практики ==&lt;br /&gt;
&lt;br /&gt;
# '''Нижняя граница.''' Докажите, что любая сравнительная сортировка делает &amp;lt;math&amp;gt;\Omega(n\log n)&amp;lt;/math&amp;gt; сравнений. ''Подсказка:'' дерево решений и &amp;lt;math&amp;gt;n!&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
# '''Counting sort.''' Реализуйте устойчивую сортировку подсчётом и проверьте на дубликатах. ''Подсказка:'' проход справа налево.&lt;br /&gt;
&lt;br /&gt;
# '''Radix.''' Отсортируйте 32-битные числа поразрядно и сравните время с &amp;lt;code&amp;gt;std::sort&amp;lt;/code&amp;gt;. ''Подсказка:'' 4 прохода по байтам.&lt;br /&gt;
&lt;br /&gt;
# '''Устойчивость.''' Определите, какие из quicksort/heapsort/mergesort/Timsort устойчивы, и приведите контрпример для неустойчивого.&lt;br /&gt;
&lt;br /&gt;
# '''Худший вход.''' Постройте вход, дающий quicksort &amp;lt;math&amp;gt;\Theta(n^2)&amp;lt;/math&amp;gt;, и проверьте подсчётом.&lt;br /&gt;
&lt;br /&gt;
# '''Гибрид.''' Скомбинируйте quicksort и сортировку вставками при &amp;lt;math&amp;gt;n &amp;lt; 16&amp;lt;/math&amp;gt;; сравните число сравнений.&lt;br /&gt;
&lt;br /&gt;
# '''Выбор.''' Для задачи «устойчиво отсортировать по двум ключам» выберите алгоритм и объясните. ''Подсказка:'' сначала по второстепенному, затем устойчиво по главному.&lt;br /&gt;
&lt;br /&gt;
# '''Оценка ключей.''' Когда counting sort быстрее mergesort? Выведите условие через &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;. ''Подсказка:'' &amp;lt;math&amp;gt;n + k&amp;lt;/math&amp;gt; против &amp;lt;math&amp;gt;n\log n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Связанные темы ==&lt;br /&gt;
&lt;br /&gt;
* [[Быстрая сортировка]] — средняя скорость, introsort.&lt;br /&gt;
* [[Сортировка слиянием]] — устойчивость и гарантия.&lt;br /&gt;
* [[Пирамидальная сортировка]] — гарантия при &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; памяти.&lt;br /&gt;
* [[Сортировка вставками]] — база гибридов; адаптивность и малые массивы.&lt;br /&gt;
* [[Сортировка Шелла]], [[Сортировка выбором]], [[Сортировка пузырьком]] — элементарные сортировки-родственники.&lt;br /&gt;
* [[Timsort]] — адаптивность и устойчивость.&lt;br /&gt;
* [[Асимптотическая сложность]] — нижние границы и рекуррентности.&lt;br /&gt;
* [[Графы]] — многие графовые задачи начинаются с сортировки рёбер/вершин.&lt;br /&gt;
&lt;br /&gt;
== Источники ==&lt;br /&gt;
&lt;br /&gt;
# Cormen T. H., Leiserson C. E., Rivest R. L., Stein C. ''Introduction to Algorithms'' (CLRS). 3rd ed. — MIT Press, 2009. — Гл. 2, 6, 7, 8 (mergesort, heapsort, quicksort, сортировка за линейное время и нижняя граница).&lt;br /&gt;
# Sedgewick R., Wayne K. ''Algorithms''. 4th ed. — Addison-Wesley, 2011. — Гл. 2 (сортировки), приложения к внешней сортировке.&lt;br /&gt;
# Silberschatz A., Korth H. F., Sudarshan S. ''Database System Concepts''. — McGraw-Hill, 7th ed., 2019 (внешняя сортировка, sort-merge join).&lt;br /&gt;
# Peters T. listsort.txt (Timsort). URL: https://github.com/python/cpython/blob/main/Objects/listsort.txt.&lt;br /&gt;
# Knuth D. E. ''The Art of Computer Programming''. Vol. 3: Sorting and Searching. — Addison-Wesley, 2nd ed., 1998 (алгоритмы, нижние границы, radix, внешняя сортировка).&lt;br /&gt;
# Hoare C. A. R. Quicksort // The Computer Journal. — 1962. — Vol. 5, № 1.&lt;br /&gt;
# Williams J. W. J. Algorithm 232: Heapsort // CACM. — 1964; Floyd R. W. Algorithm 245: Treesort // CACM. — 1964.&lt;br /&gt;
# Wikipedia: Sorting algorithm. URL: https://en.wikipedia.org/wiki/Sorting_algorithm .&lt;br /&gt;
&lt;br /&gt;
[[Category:Алгоритмы и структуры данных|Сортировки]]&lt;/div&gt;</summary>
		<author><name>СВ</name></author>
	</entry>
</feed>