Я использую JDK-8 (x64). Для Arrays.sort
(примитивов) я нашел в документации по Java следующее:
Алгоритм сортировки - это Dual-Pivot Quicksort от Владимира Ярославского, Джона Бентли и Джошуа Блоха.
Для Collections.sort
(объектов) я нашел этот "Тимсорт":
Эта реализация представляет собой стабильную, адаптивную, итеративную сортировку слиянием ... Эта реализация выгружает указанный список в массив, сортирует массив и выполняет итерацию по списку, сбрасывая каждый элемент из соответствующей позиции в массиве.
Если Collections.sort
используется массив, почему он просто не вызывает Arrays.sort
или не использует QuickSort с двумя поворотами ? Зачем использовать Mergesort ?
Ответы:
API гарантирует стабильную сортировку, чего не предлагает Quicksort . Однако при сортировке примитивных значений по их естественному порядку вы не заметите разницы, поскольку примитивные значения не имеют идентичности. Следовательно, быстрая сортировка может использоваться для примитивных массивов и будет использоваться, когда будет сочтена более эффективной¹.
Для объектов вы можете заметить, когда объекты с разными идентификаторами, которые считаются равными в зависимости от их
equals
реализации или предоставленного,Comparator
изменяют свой порядок. Таким образом, Quicksort не вариант. Таким образом, используется вариант MergeSort , текущие версии Java используют TimSort . Это применимо к обоим,Arrays.sort
иCollections.sort
, хотя в Java 8,List
сам по себе может переопределить алгоритмы сортировки.¹ Преимущество быстрой сортировки в эффективности заключается в том, что при выполнении на месте требуется меньше памяти. Но он имеет потрясающую производительность в худшем случае и не может использовать прогоны предварительно отсортированных данных в массиве, что делает TimSort .
Поэтому алгоритмы сортировки переделывались от версии к версии, оставаясь при этом в классе, который теперь неправильно назван
DualPivotQuicksort
. Кроме того, документация не обновилась, что показывает, что в целом плохая идея - указывать в спецификации внутренний алгоритм, когда в этом нет необходимости.Текущая ситуация (включая Java 8 - Java 11) выглядит следующим образом:
sort(char[],…)
иsort(short[],…)
добавьте еще один особый случай, чтобы использовать сортировку с подсчетом для массивов, длина которых превышает определенный порогsort(byte[],…)
будет использоваться сортировка подсчетом , но с гораздо меньшим порогом, что создает самый большой контраст с документацией, посколькуsort(byte[],…)
никогда не использует быструю сортировку. Он использует только сортировку вставкой для небольших массивов и сортировку подсчетом в противном случае.источник
List.sort
метод переопределения .Collections.sort
никогда не может гарантировать правильную работу для каждойList
реализации, так как не может гарантировать, например, чтоList
он не изменяет свое содержимое ложным образом. Это все сводится к тому , что гарантияCollections.sort
относится только к правильнойList
реализации (и правильноComparator
илиequals
реализации).Collections.sort
делегирование будет выполнятьсяList.sort
.Collections.sort
даже не упоминает в своей сигнатуре типа, что вывод отсортирован?Collections.sort
будет чем-то вроде «коллекция того же типа и длины, что и вход, со свойствами, которые: 1) каждый элемент, присутствующий во входных данных, также присутствует в выходных данных, 2 ) для каждой пары элементов из выхода, левый не больше правого, 3) для каждой пары равных элементов из выхода, индекс левого на входе меньше правого "или что-то вроде что.Я не знаю о документации, но реализация
java.util.Collections#sort
в Java 8 (HotSpot) выглядит следующим образом:@SuppressWarnings({"unchecked", "rawtypes"}) public static <T> void sort(List<T> list, Comparator<? super T> c) { list.sort(c); }
И
List#sort
имеет эту реализацию:@SuppressWarnings({"unchecked", "rawtypes"}) default void sort(Comparator<? super E> c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator<E> i = this.listIterator(); for (Object e : a) { i.next(); i.set((E) e); } }
Итак, в конце концов,
Collections#sort
используетArrays#sort
(элементов объекта) за кадром. В этой реализации используется сортировка слиянием или сортировка по времени.источник
Согласно Javadoc, только примитивные массивы сортируются с использованием Quicksort. Массивы объектов также сортируются с помощью сортировки слиянием.
Итак, Collections.sort, похоже, использует тот же алгоритм сортировки, что и Arrays.sort для объектов.
Другой вопрос, почему для примитивных массивов используется другой алгоритм сортировки, чем для массивов объектов?
источник
Как указано во многих ответах.
Быстрая сортировка используется Arrays.sort для сортировки примитивных коллекций, потому что стабильность не требуется (вы не будете знать и не заботитесь, были ли поменяны местами два идентичных целых числа при сортировке)
MergeSort или, более конкретно, Timsort используется Arrays.sort для сортировки коллекций объектов. Требуется стабильность. Quicksort не обеспечивает стабильности, Timsort обеспечивает.
Collections.sort делегирует Arrays.sort, поэтому вы видите javadoc, ссылающийся на MergeSort.
источник
Быстрая сортировка имеет два основных недостатка, когда дело доходит до сортировки слиянием:
Стабильность не является проблемой для примитивных типов, поскольку нет понятия идентичности, отличного от (значения) равенства.
Стабильность очень важна при сортировке произвольных объектов. Хорошим дополнительным преимуществом является то, что сортировка слиянием гарантирует производительность n log n (время) независимо от входных данных. Вот почему выбрана сортировка слиянием, чтобы обеспечить стабильную сортировку (сортировку слиянием) для сортировки ссылок на объекты.
источник