Estou usando o JDK-8 (x64). Para Arrays.sort
(primitivos), encontrei o seguinte na documentação do Java:
O algoritmo de classificação é um Quicksort Dual-Pivot de Vladimir Yaroslavskiy, Jon Bentley e Joshua Bloch.
Para Collections.sort
(objetos), encontrei este "Timsort":
Esta implementação é um mergesort estável, adaptável e iterativo ... Esta implementação despeja a lista especificada em uma matriz, classifica a matriz e itera sobre a lista, redefinindo cada elemento da posição correspondente na matriz.
Se Collections.sort
usa uma matriz, por que simplesmente não chama Arrays.sort
ou usa QuickSort dual-pivot ? Por que usar Mergesort ?
Respostas:
A API garante uma classificação estável que Quicksort não oferece. No entanto, ao classificar os valores primitivos por sua ordem natural, você não notará a diferença, pois os valores primitivos não têm identidade. Portanto, Quicksort pode ser usado para arrays primitivos e será usado quando for considerado mais eficiente¹.
Para objetos, você pode notar, quando objetos com identidade diferente que são considerados iguais de acordo com sua
equals
implementação ou o fornecidoComparator
mudam sua ordem. Portanto, Quicksort não é uma opção. Portanto, uma variante de MergeSort é usada, as versões atuais do Java usam TimSort . Isso se aplica a ambosArrays.sort
eCollections.sort
, embora com Java 8, oList
próprio pode substituir os algoritmos de classificação.¹ A vantagem de eficiência do Quicksort é a necessidade de menos memória quando feito no local. Mas tem um desempenho dramático no pior caso e não pode explorar execuções de dados pré-classificados em um array, o que o TimSort faz.
Portanto, os algoritmos de classificação foram retrabalhados de versão para versão, enquanto permaneciam na classe agora erroneamente nomeada
DualPivotQuicksort
. Além disso, a documentação não alcançou o atraso, o que mostra que é uma má ideia em geral, nomear um algoritmo usado internamente em uma especificação, quando não necessário.A situação atual (incluindo Java 8 a Java 11) é a seguinte:
sort(char[],…)
esort(short[],…)
adicionar outro caso especial, para usar a classificação por contagem para matrizes cujo comprimento excede um certo limitesort(byte[],…)
usará a classificação por contagem , mas com um limite muito menor, o que cria o maior contraste com a documentação, já quesort(byte[],…)
nunca usa Quicksort. Ele só usa a classificação por inserção para pequenos arrays e, caso contrário, a classificação por contagem .fonte
List.sort
método de substituição .Collections.sort
nunca poderia garantir o funcionamento correto para cadaList
implementação, uma vez que não pode garantir, por exemplo, que oList
não altera seu conteúdo de forma espúria. Tudo se resume a que a garantia deCollections.sort
apenas se aplica aList
implementações corretas (e corretasComparator
ouequals
implementações).Collections.sort
irá delegar paraList.sort
.Collections.sort
nem mesmo menciona em sua assinatura de tipo que a saída está classificada?Collections.sort
seria algo como "uma coleção do mesmo tipo e comprimento da entrada com as propriedades que 1) cada elemento presente na entrada também está presente na saída, 2 ) para cada par de elementos da saída, o esquerdo não é maior que o direito, 3) para cada par de elementos iguais da saída, o índice do esquerdo na entrada é menor que o direito "ou algo como aquele.Não sei sobre a documentação, mas a implementação do
java.util.Collections#sort
em Java 8 (HotSpot) é assim:E
List#sort
tem esta implementação:Então, no final,
Collections#sort
usaArrays#sort
(de elementos de objeto) nos bastidores. Esta implementação usa merge sort ou tim sort.fonte
De acordo com o Javadoc, apenas arrays primitivos são classificados usando Quicksort. Matrizes de objetos são classificadas com um Mergesort também.
Portanto, Collections.sort parece usar o mesmo algoritmo de classificação que Arrays.sort para Objetos.
Outra questão seria por que um algoritmo de classificação diferente é usado para matrizes primitivas e não para matrizes de objetos?
fonte
Conforme afirmado em muitas das respostas.
O Quicksort é usado por Arrays.sort para classificar coleções primitivas porque a estabilidade não é necessária (você não saberá ou se importará se dois ints idênticos foram trocados na classificação)
MergeSort ou mais especificamente Timsort é usado por Arrays.sort para classificar coleções de objetos. A estabilidade é necessária. O Quicksort não oferece estabilidade, mas o Timsort.
Collection.sort delega para Arrays.sort, razão pela qual você vê o javadoc referenciando o MergeSort.
fonte
A classificação rápida tem duas desvantagens principais quando se trata de classificação por mesclagem:
A estabilidade não é um problema para os tipos primitivos, pois não há noção de identidade distinta da igualdade (de valor).
A estabilidade é um grande problema ao classificar objetos arbitrários. É um bom benefício colateral que Merge Sort garante desempenho n log n (tempo), independentemente da entrada. É por isso que merge sort é selecionado para fornecer uma ordenação estável (Merge Sort) para ordenar referências de objetos.
fonte