Почему мы не используем попытки сортировки, если они занимают O (n) время для сортировки списка? - PullRequest
4 голосов
/ 23 февраля 2020

Вот описание алгоритма сортировки строк с использованием tr ie:

Алгоритм сначала вставляет все элементы в tr ie за O(n) времени, где n - это общее количество. количество символов в списке слов, которые должны быть отсортированы.

Затем он пересекает дерево по порядку, распечатывая узел, которому предшествует его префикс, когда дело доходит до узла с установленным флагом is_end. Это требует полного обхода tr ie, что занимает O(m) времени, где m - количество узлов в tr ie. Это ограничено n, поэтому этот шаг также ограничен O(n).

Весь алгоритм состоит из двух подпрограмм, каждая из которых ограничена O(n). Например, если мы говорим, что среднее слово содержит c символов, то, если m - это количество слов, cm == n, а общее время выполнения ограничено O(n) == O(cm) == O(m) (причина, по которой я изменил его на m, такова: потому что это традиционная мера длины списка, который нужно отсортировать, а не общее количество символов).

Поэтому мой вопрос: если этот анализ времени выполнения верен, почему это не метод по умолчанию для сортировки строк, как это было бы быстрее, чем любой O(nlogn) алгоритм сортировки?

1 Ответ

8 голосов
/ 23 февраля 2020

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

Обратите внимание, что здесь O (n log n) является нижней границей количества сравнений, а не времени выполнения. Если сравнение занимает больше чем O (1) раз, скажем, из-за того, что вы сравниваете длинные строки, которые имеют длинные общие префиксы, тогда время выполнения будет похоже на O (cn log n), где сравнение выполняется в O (c Время Например, сравнение строк длины w в худшем случае занимает время O (w).


Если вам нужен только алгоритм сортировки для данных определенного типа c, то вы можете сделать лучше, потому что другие элементы, указывающие c на этот тип данных, могут быть выполнены над элементами Например, при сортировке целых чисел вы можете использовать элементы массива для индексации другого массива, давая алгоритм counting sort , который выполняется за время O (n + r), где r - диапазон элементов массива.

Если ключи сортировки похожи на строки, в том смысле, что они являются (или могут быть сопоставлены) последовательностями, так что сравнение ключей эквивалентно лексикографическому сравнению этих последовательностей тогда вы действительно можете использовать tr ie для сортировки массива, содержащего этот тип данных. Поздравляем: вы независимо друг от друга заново изобрели алгоритм radix sort , который можно реализовать с помощью попыток . Время его выполнения составляет O (wn), а не O (n), потому что для вставки строки длины w в tr ie требуется время O (w), и вы должны сделать это n раз.


Итак, если элементы не являются строками или «подобны строкам» в вышеприведенном смысле, тогда сортировка по основанию просто не применима. Если элементы являются строками или «строковыми», тогда сортировка по основанию работает, но вместо O (wn log n) требуется время O (wn).

Это означает, что сортировка по основанию не является строго лучше, и вероятно, хуже, когда общие префиксы строк короткие по отношению к самим строкам, что часто имеет место. Для случайных строк обычное сравнение строк занимает в среднем O (1) времени, в этом случае O (n log n) асимптотически лучше, чем сортировка по основанию для строк длиннее, чем O (log n).

В практических приложениях Также следует учитывать скрытые константы в анализе асимптотики c. Сорта сравнения, такие как Timsort , имеют малые скрытые константы, потому что они последовательно обращаются к элементам массива, что приводит к меньшему количеству пропусков кэша по сравнению с обходом дерева, узлы которого не будут последовательными в памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...