Comparação de tempo de Arrays.sort (Object []) e Arrays.sort (int [])
1. Visão geral
Neste tutorial rápido,we’ll compare the two Arrays.sort(Object[]) and Arrays.sort(int[]) sorting operations.
Primeiro, vamos descrever cada método separadamente. Depois disso, vamos escrever testes de desempenho para medir seus tempos de execução.
2. Arrays.sort(Object[])
Antes de prosseguirmos, é importante ter em mente queArrays.sort() muda para matrizes de tipo primitivo e de referência.
Arrays.sort(Object[]) accepts reference types.
Por exemplo, temos uma matriz deInteger objetos:
Integer[] numbers = {5, 22, 10, 0};
Para classificar a matriz, podemos simplesmente usar:
Arrays.sort(numbers);
Agora, a matriz de números tem todos os seus elementos em ordem crescente:
[0, 5, 10, 22]
Arrays.sort(Object[]) é baseado no algoritmo TimSort,giving us a time complexity of O(n log(n)). Resumindo, TimSort usa os algoritmosInsertion sorteMergeSort. No entanto, ainda é mais lento em comparação com outros algoritmos de classificação, como algumas das implementações do QuickSort.
3. Arrays.sort(int[])
Por outro lado,Arrays.sort(int[]) works with primitive int arrays.
Da mesma forma, podemos definir uma matrizint[] de primitivas:
int[] primitives = {5, 22, 10, 0};
E classifique-o com outra implementação deArrays.sort(int[]). Desta vez, aceitando uma matriz de primitivas:
Arrays.sort(primitives);
O resultado desta operação não será diferente do exemplo anterior. E os itens na matrizprimitives serão parecidos com:
[0, 5, 10, 22]
Sob o capô, ele usa Dual-PivotQuicksort algorithm. Sua implementação interna do JDK 10 é tipicamente mais rápida que o Quicksort tradicional de um pivô.
This algorithm offers O(n log(n)) averagetime complexity. Esse é um ótimo tempo médio de classificação para muitas coleções. Além disso, ele tem a vantagem de estar completamente no lugar, portanto não requer armazenamento adicional.
Porém,in the worst case, its time complexity is O(n2).
4. Comparação de Tempo
Então, qual algoritmo é mais rápido e por quê? Vamos primeiro fazer um pouco de teoria e, em seguida, vamos executar alguns testes concretos com JMH.
4.1. Análise qualitativa
Arrays.sort(Object[]) is typically slower compared to Arrays.sort(int[]) por alguns motivos diferentes.
O primeiro são os diferentes algoritmos. QuickSort is often faster than Timsort.
O segundo é como cada método compara os valores.
Veja,since Arrays.sort(Object[]) needs to compare one object against another, it needs to call each element’s compareTo method. No mínimo, isso requer uma pesquisa de método e enviar uma chamada para a pilha, além do que a operação de comparação realmente é.
Por outro lado,Arrays.sort(int[]) can simply use primitive relational operators like < and >, que são instruções de bytecode único.
4.2. Parâmetros JMH
Finalmente, vamos descobrirwhich sorting method runs faster with actual data. Para isso, usaremos a ferramentaJMH (Java Microbenchmark Harness) para escrever nossos testes de benchmark.
Então, vamos fazer uma referência muito simples aqui. Não é abrangente, maswill give us an idea of how we can approach comparando os métodos de classificaçãoArrays.sort(int[])eArrays.sort(Integer[]).
Em nossa aula de benchmark, usaremos anotações de configuração:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Measurement(batchSize = 100000, iterations = 10)
@Warmup(batchSize = 100000, iterations = 10)
public class ArraySortBenchmark {
}
Aqui, queremos medir o tempo médio para uma única operação (Mode.AverageTime)e exibir nossos resultados em milissegundos (TimeUnit.MILLISECONDS). Além disso, com o parâmetrobatchSize, estamos dizendo ao JMH para realizar 100.000 iterações para garantir que nossos resultados tenham alta precisão.
4.3. Testes de referência
Antes de executar os testes, precisamos definir os contêineres de dados que queremos classificar:
@State(Scope.Thread)
public static class Initialize {
Integer[] numbers = {-769214442, -1283881723, 1504158300, -1260321086, -1800976432, 1278262737,
1863224321, 1895424914, 2062768552, -1051922993, 751605209, -1500919212, 2094856518,
-1014488489, -931226326, -1677121986, -2080561705, 562424208, -1233745158, 41308167 };
int[] primitives = {-769214442, -1283881723, 1504158300, -1260321086, -1800976432, 1278262737,
1863224321, 1895424914, 2062768552, -1051922993, 751605209, -1500919212, 2094856518,
-1014488489, -931226326, -1677121986, -2080561705, 562424208, -1233745158, 41308167};
}
Vamos escolher oInteger[] numbers lixar a matrizint[]primitives de elementos primitivos. A anotação@State indica que as variáveis declaradas na classe não farão parte dos testes de benchmark em execução. No entanto, podemos usá-los em nossos métodos de benchmark.
Agora, estamos prontos para adicionar o primeiro micro-benchmark paraArrays.sort(Integer[]):
@Benchmark
public Integer[] benchmarkArraysIntegerSort(ArraySortBenchmark.Initialize state) {
Arrays.sort(state.numbers);
return state.numbers;
}
A seguir, paraArrays.sort(int[]):
@Benchmark
public int[] benchmarkArraysIntSort(ArraySortBenchmark.Initialize state) {
Arrays.sort(state.primitives);
return state.primitives;
}
4.4. Resultado dos testes
Por fim, executamos nossos testes e comparamos os resultados:
Benchmark Mode Cnt Score Error Units
benchmarkArraysIntSort avgt 10 1.095 ± 0.022 ms/op
benchmarkArraysIntegerSort avgt 10 3.858 ± 0.060 ms/op
A partir dos resultados, podemos ver queArrays.sort(int[]) method performed better than to Arrays.sort(Object[]) em nosso teste, provavelmente pelas razões anteriores que identificamos.
E, embora os números pareçam apoiar nossa teoria, precisaríamos fazer testes com uma variedade maior de entradas para ter uma ideia melhor.
Além disso,keep in mind that the numbers we present here are just JMH benchmark results - portanto, devemos sempre testar no escopo de nosso próprio sistema e tempo de execução.
4.5. Por que Timsort então?
Provavelmente deveríamos nos fazer uma pergunta, então. If QuickSort is faster, why not use it for both implementations?
Veja,QuickSort isn’t stable, então não podemos usá-lo para classificarObjects. Basicamente, se doisints forem iguais, não importa que sua ordem relativa permaneça a mesma, pois um2 não é diferente de outro2. Com objetos, porém, podemos classificar por um atributo e depois outro, tornando a ordem inicial importante.
5. Conclusão
Neste artigo,we compared two sorting methods available in Java: Arrays.sort(int[]) and Arrays.sort(Integer[]*)*. Além disso, discutimos os algoritmos de classificação usados em suas implementações.
Finalmente, com a ajuda de testes de desempenho de benchmark, mostramos um tempo de execução de amostra de cada opção de classificação .
Como de costume, o código completo deste artigo está disponívelover on GitHub.