Сортировка строк

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

Суть урока. Сортировка строк имеет фундаментальное отличие от сортировки чисел. Сравнение двух целых чисел занимает время O(1). А вот сравнение двух строк длины L в худшем случае занимает время O(L). Из-за этого классические алгоритмы (сортировка Хоара, сортировка слиянием) работают со строками медленнее, чем мы ожидаем.

Проблема скрытой константы O(L)

Когда мы оцениваем сложность алгоритмов сортировки, мы обычно говорим про количество сравнений элементов. Например, сортировка слиянием делает O(N log N) сравнений, где N - количество элементов.

Но если элементами являются строки (или длинные массивы), само сравнение перестает быть мгновенным. Чтобы понять, что строка "алгоритм" меньше строки "алгоритмы", нам нужно посимвольно сравнить их. Если строки почти идентичны и различаются только в самом конце, сравнение потребует прохода по всем символам.

Специфичные алгоритмы для строк

Вместо того чтобы сравнивать строки целиком (как монолитные объекты), гораздо эффективнее рассматривать их как последовательность символов. Существуют алгоритмы, которые вообще не используют прямое сравнение строк друг с другом:

1. Цифровая сортировка (Radix Sort) для строк

Мы можем сортировать строки посимвольно (как разряды в числах).

Поразрядная сортировка строк MSD
Поразрядная сортировка строк по старшим символам: рекурсивное распределение строк по корзинам первой несовпадающей буквы.

Алгоритм поразрядной сортировки работает следующим образом:

  1. Массив строк разбивается на корзины на основе первого символа.
  2. Внутри каждой непустой корзины алгоритм рекурсивно сортирует строки уже по второму символу, и так далее.
  3. После распределения результаты конкатенируются в итоговый отсортированный массив.

2. Префиксные деревья (Trie)

Можно вставить все строки в специальную структуру данных - префиксное дерево (Trie). Вставка N строк длины L займет время O(N * L). Затем мы просто обходим это дерево в глубину (DFS) и выписываем слова в алфавитном порядке. Это элегантное и быстрое решение, но оно потребляет очень много оперативной памяти для хранения узлов дерева.

3. Трехпутевая быстрая сортировка строк (3-Way Radix Quick Sort)

Это гибрид сортировки Хоара и MSD цифровой сортировки. Разработан Робертом Седжвиком. На каждом шаге выбирается один опорный символ (pivot), и массив строк разбивается на три части: те, где текущий символ меньше опорного, равен опорному и больше опорного. Алгоритм отлично справляется с массивами, где много строк с общими префиксами.

Лексикографический порядок
При сортировке строк используется лексикографический (алфавитный) порядок. Он опирается на коды символов в таблице кодировок (ASCII или Unicode). Из-за этого заглавные буквы обычно идут раньше строчных (код 'A' = 65, код 'a' = 97), а цифры раньше букв.

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

  • Сравнение двух длинных строк не является мгновенным и в худшем случае занимает время O(L).
  • Обычные алгоритмы (сортировка слиянием, сортировка Хоара) на массиве строк длины L работают за O(N * L * log N).
  • Для эффективной сортировки строк используют алгоритмы, рассматривающие строки посимвольно.
  • MSD/LSD Radix Sort, префиксные деревья (Trie) и трехпутевая быстрая сортировка строк позволяют избежать прямых сравнений слов целиком.
  • При сортировке строк учитывается лексикографический порядок (коды символов в таблице кодировок).

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

Чему равна временная сложность классической сортировки слиянием для массива из N строк, каждая из которых имеет длину L?

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