Estoy usando JDK-8 (x64). Para Arrays.sort
(primitivas) encontré lo siguiente en la documentación de Java:
El algoritmo de clasificación es un Quicksort de doble pivote de Vladimir Yaroslavskiy, Jon Bentley y Joshua Bloch.
Para Collections.sort
(objetos) encontré este "Timsort":
Esta implementación es un mergesort iterativo, adaptable, estable ... Esta implementación vuelca la lista especificada en una matriz, ordena la matriz e itera sobre la lista restableciendo cada elemento desde la posición correspondiente en la matriz.
Si Collections.sort
usa una matriz, ¿por qué no simplemente llama Arrays.sort
o usa QuickSort de doble pivote ? ¿Por qué utilizar Mergesort ?
Respuestas:
La API garantiza una clasificación estable que Quicksort no ofrece. Sin embargo, al ordenar los valores primitivos por su orden natural, no notará una diferencia ya que los valores primitivos no tienen identidad. Por lo tanto, Quicksort se puede usar para matrices primitivas y se usará cuando se considere más eficiente¹.
En el caso de los objetos, puede observar cuando los objetos con una identidad diferente que se consideran iguales según su
equals
implementación o la proporcionadaComparator
cambian su orden. Por lo tanto, Quicksort no es una opción. Entonces se usa una variante de MergeSort , las versiones actuales de Java usan TimSort . Esto se aplica a ambosArrays.sort
yCollections.sort
, aunque con Java 8, elList
mismo puede anular los algoritmos de ordenación.¹ La ventaja de eficiencia de Quicksort es que necesita menos memoria cuando se realiza en el lugar. Pero tiene un rendimiento dramático en el peor de los casos y no puede explotar las ejecuciones de datos preordenados en una matriz, lo que hace TimSort .
Por lo tanto, los algoritmos de clasificación se modificaron de una versión a otra, mientras permanecían en la clase que ahora tiene un nombre engañoso
DualPivotQuicksort
. Además, la documentación no se puso al día, lo que muestra que, en general, es una mala idea nombrar un algoritmo utilizado internamente en una especificación, cuando no es necesario.La situación actual (incluyendo Java 8 a Java 11) es la siguiente:
sort(char[],…)
ysort(short[],…)
agregue otro caso especial, para usar la clasificación de conteo para matrices cuya longitud exceda un cierto umbralsort(byte[],…)
usará la ordenación por conteo , pero con un umbral mucho más pequeño, lo que crea el mayor contraste con la documentación, ya quesort(byte[],…)
nunca usa ordenación rápida. Solo usa la ordenación por inserción para matrices pequeñas y la ordenación por conteo en caso contrario.fuente
List.sort
método primordial .Collections.sort
nunca podría garantizar el funcionamiento correcto para cadaList
implementación, ya que no puede garantizar, por ejemplo, queList
no cambie su contenido de manera falsa. Todo se reduce a que la garantía deCollections.sort
solo se aplica aList
implementaciones correctas (y correctasComparator
oequals
implementaciones).Collections.sort
delegará enList.sort
.Collections.sort
ni siquiera menciona en su firma de tipo que la salida está ordenada?Collections.sort
sería algo así como "una colección del mismo tipo y longitud que la entrada con las propiedades de que 1) cada elemento presente en la entrada también está presente en la salida, 2 ) para cada par de elementos de la salida, el de la izquierda no es mayor que el de la derecha, 3) para cada par de elementos iguales de la salida, el índice de la izquierda en la entrada es más pequeño que el de la derecha "o algo así como ese.No sé acerca de la documentación, pero la implementación de
java.util.Collections#sort
Java 8 (HotSpot) es así:Y
List#sort
tiene esta implementación:Entonces, al final, los
Collections#sort
usosArrays#sort
(de elementos de objeto) detrás de escena. Esta implementación utiliza ordenación por fusión o ordenación por tiempo.fuente
Según el Javadoc, solo las matrices primitivas se ordenan usando Quicksort. Las matrices de objetos también se ordenan con Mergesort.
Por lo tanto, Collections.sort parece usar el mismo algoritmo de clasificación que Arrays.sort para Objetos.
Otra pregunta sería por qué se usa un algoritmo de clasificación diferente para matrices primitivas que para matrices de objetos.
fuente
Como se indica en muchas de las respuestas.
Arrays.sort utiliza Quicksort para ordenar colecciones primitivas porque no se requiere estabilidad (no sabrá ni le importará si se intercambiaron dos entradas idénticas en la ordenación)
Arrays.sort usa MergeSort o más específicamente Timsort para ordenar colecciones de objetos. Se requiere estabilidad. Quicksort no proporciona estabilidad, Timsort sí.
Collections.sort delega a Arrays.sort, por lo que ve el javadoc haciendo referencia a MergeSort.
fuente
La ordenación rápida tiene dos inconvenientes importantes cuando se trata de la ordenación combinada:
La estabilidad no es un problema para los tipos primitivos, ya que no existe una noción de identidad a diferencia de la igualdad (de valores).
La estabilidad es un gran problema al clasificar objetos arbitrarios. Es un buen beneficio adicional que Merge Sort garantiza un rendimiento n log n (tiempo) sin importar la entrada. Es por eso que se selecciona la clasificación por combinación para proporcionar una clasificación estable (clasificación por combinación) para ordenar las referencias de objetos.
fuente