Classificação do Shell em Java
1. Introdução
Neste tutorial, descreveremos o algoritmo de classificação Shell em Java.
2. Visão geral da classificação do shell
2.1. Descrição
Vamos primeiro descrever o algoritmo de classificação Shell para que saibamos o que estamos tentando implementar.
A classificação de shell é baseada emInsertion sorting algorithm e pertence ao grupo de algoritmos muito eficientes. Em geral,the algorithm breaks an original set into smaller subsets and then each of those is sorted using Insertion sort.
Mas, como isso torna os subconjuntos não é simples. Ele não escolhe elementos vizinhos para formar um subconjunto como poderíamos esperar. Em vez disso, a classificação de shell usa os chamadosinterval ougap para a criação de subconjunto. Por exemplo, se temos a lacunaI, isso significa que um subconjunto conterá o elementos que estãoI posições separadas.
Em primeiro lugar, o algoritmo classifica os elementos que estão distantes uns dos outros. Em seguida, a lacuna torna-se menor e os elementos mais próximos são comparados. Dessa forma, alguns elementos que não estão em uma posição correta podem ser posicionados mais rápido do que se fizéssemos os subconjuntos com os elementos vizinhos.
2.2. Um exemplo
Vejamos isso no exemplo com as lacunas de 3 e 1 e a lista não classificada de 9 elementos:
Se seguirmos a descrição acima, na primeira iteração, teremos três subconjuntos com 3 elementos (destacados pela mesma cor):
Depois de classificar cada um dos subconjuntos na primeira iteração, a lista ficaria assim:
Podemos notar que, embora ainda não tenhamos uma lista classificada, os elementos agora estão mais próximos das posições desejadas.
Finalmente, precisamos fazer mais uma classificação com o incremento de um e, na verdade, é uma classificação de inserção básica. O número de operações de deslocamento que precisamos realizar para classificar uma lista agora é menor do que seria se não fizéssemos a primeira iteração:
2.3. Escolhendo as sequências de gap
Como mencionamos, a classificação de shell tem uma maneira única de escolher sequências de lacunas. Esta é uma tarefa difícil e devemos ter cuidado para não escolher lacunas demais ou insuficientes. Mais detalhes podem ser encontrados emmost proposed gap sequences listing.
3. Implementação
Vamos agora dar uma olhada na implementação. Usaremos a sequência original do Shell para incrementos de intervalo:
N/2, N/4, …, 1 (continuously dividing by 2)
A implementação em si não é muito complexa:
public void sort(int arrayToSort[]) {
int n = arrayToSort.length;
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i++) {
int key = arrayToSort[i];
int j = i;
while (j >= gap && arrayToSort[j - gap] > key) {
arrayToSort[j] = arrayToSort[j - gap];
j -= gap;
}
arrayToSort[j] = key;
}
}
}
Primeiro, criamos uma sequência de lacunas com um loop for e, em seguida, fizemos a classificação de inserção para cada tamanho de lacuna.
Agora, podemos facilmente testar nosso método:
@Test
public void givenUnsortedArray_whenShellSort_thenSortedAsc() {
int[] input = {41, 15, 82, 5, 65, 19, 32, 43, 8};
ShellSort.sort(input);
int[] expected = {5, 8, 15, 19, 32, 41, 43, 65, 82};
assertArrayEquals("the two arrays are not equal", expected, input);
}
4. Complexidade
Geralmente,the Shell sort algorithm is very efficient with medium-sized lists. A complexidade é difícil de determinar, pois depende muito da sequência de lacunas, mas a complexidade do tempo varia entreO(N)eO(N^2).
O pior caso de complexidade de espaço éO(N) comO(1) espaço auxiliar.
5. Conclusão
Neste tutorial, descrevemos a classificação do Shell e ilustramos como podemos implementá-lo em Java.
Como de costume, todo o código pode ser encontradoover on GitHub.