Сортировка подсчётом (counting sort) считает, сколько раз встречается каждое значение, и по этим счётчикам выстраивает результат. Работает за , где значения — целые числа от до .
Зачем нужно
Любая сортировка сравнением не быстрее (см. Сортировка). Если значения — небольшие целые числа, можно вообще не сравнивать: использовать значение как индекс. Тогда сортировка идёт за линейное время.
Как работает
Простая версия
count = [0 ... 0] // K + 1
for i = 0 ... N
count[arr[i]]++
for i = 0 ... K
while count[i] > 0
print(i)
count[i]--: первый цикл — шагов, во втором значений и всего печатей. Она печатает значения, а не переставляет элементы. Для чисел этого достаточно, для записей по ключу — нет: на лекции эта версия названа неустойчивой.
Устойчивая версия
count = [0 ... 0] // K + 1
result = [ ... ] // N
for i = 0 ... N
count[arr[i]]++
for i = 1 ... K
count[i] += count[i − 1]
for j = N − 1 ... 0
result[count[arr[j]] − 1] = arr[j]
count[arr[j]]--После префиксных сумм count[v] — число элементов : значения
занимают в результате позиции [count[v−1], count[v]). Проход с конца
кладёт самый правый из равных на последнее место блока, следующий — левее.
Порядок равных сохраняется — сортировка устойчива. Пример: счётчики
5 7 9 1 5 → префиксные суммы 5 12 21 22 27.
На доске
В последнем цикле записано
= arr[i]вместо= arr[j], префиксные суммы —5 13 22 23 28(ошибка в ), а оценка — , . Честно и по времени, и по памяти. См. конспект.
Тонкости
- должно быть маленьким. При время и память определяет : десять чисел до — миллиард счётчиков.
- Значения должны быть целыми неотрицательными. Отрицательные сдвигают на минимум, дробные и строки так не отсортировать.
- Нижней оценке сортировка подсчётом не противоречит: теорема говорит только о сортировках сравнением.
Не из лекции
- Сдвиг на минимум:
count[arr[i] − min]++, тогда .- Устойчивость нужна, когда подсчёт — шаг более сложной сортировки: поразрядная сортировка сортирует числа по одной цифре за проход и опирается на то, что порядок по младшим цифрам не сломается.
Частые ошибки
- Применять при огромном диапазоне значений.
- Идти в устойчивой версии с начала массива — порядок равных разворачивается.
- Забыть
− 1вresult[count[arr[j]] − 1]:count[v]указывает за последнее место блока. - Считать оценку , забыв про .