Bem-vindos ao blog Preciso Estudar Sempre. Meu nome é João Paulo Maida e minha paixão é estudar. Hoje abordaremos mais um tópico da série: Vamos por ordem nessa bagunça ? - Algoritmos de ordenação
Clique para dar uma olhada.
Neste post aprenderemos o algoritmo de ordenação Merge Sort.
AVISO: Esse algoritmo não é para iniciantes logo, você vai precisar de algum tempo para entendê-lo. Procure a supervisão de um adulto. =)
A nossa primeira pergunta é: como ele funciona ?
Criado por John von Neumann em 1945, este algoritmo utiliza a técnica de dividir para conquistar, diferentemente do seu primo, o algoritmo Bubble Sort. Possui complexidade de tempo Θ(n log 2n), no pior caso e no melhor caso, Θ(n log n).
Figura 1 - Criador do algoritmo Merge Sort |
Sua estratégia consiste em criar uma sequência ordenada a partir de outras duas já ordenadas. Para tal, divide-se a sequência original em pares de dados, e ordena-se. Depois, agrupa-se em sequências de quatro elementos, e assim por diante até a sequência original estar separada em apenas duas partes. Este processo se repete até o array estar totalmente unido e ordenado.
A imagem abaixo ilustra bem o explicado.
Figura 2 - Funcionamento do algoritmo Merge Sort |
Na etapa 4 dividimos o array até o máximo, ou seja, quando sobra somente 1 elemento, esse é o nosso caso base. A partir daí, podemos começar a ordená-lo. Na etapa 5 realizamos a primeira ordenação, ou seja, a ordenação dos pares. A partir da ordenação dos pares, podemos unir eles e ordená-los novamente, Esse processo se repete até o ponto em que obtemos o array todo unido novamente só que, agora ordenado.
O gif abaixo mostra todo o processo de ordenação de forma animada.
Figura 3 - Animação de funcionamento do algoritmo Merge Sort |
1: public class MergeSort {
2: private int[] numbers;
3: private int[] helper;
4:
5: private int number;
6:
7: public void sort(int[] values) {
8: this.numbers = values;
9: number = values.length;
10: this.helper = new int[number];
11: mergeSort(0, number - 1);
12: }
13:
14: private void mergeSort(int begin, int end) {
15: // check if begin is smaller then end, if not then the array is sorted
16: if (begin < end) {
17: // Get the index of the element which is in the middle
18: int middle = begin + (end - begin) / 2;
19: // Sort the left side of the array
20: mergeSort(begin, middle);
21: // Sort the right side of the array
22: mergeSort(middle + 1, end);
23: // Combine them both
24: merge(begin, middle, end);
25: }
26: }
27:
28: private void merge(int begin, int middle, int end) {
29:
30: // Copy both parts into the helper array
31: for (int i = begin; i <= end; i++) {
32: helper[i] = numbers[i];
33: }
34:
35: int i = begin;
36: int j = middle + 1;
37: int k = begin;
38: // Copy the smallest values from either the left or the right side back
39: // to the original array
40: while (i <= middle && j <= end) {
41: if (helper[i] <= helper[j]) {
42: numbers[k] = helper[i];
43: i++;
44: } else {
45: numbers[k] = helper[j];
46: j++;
47: }
48: k++;
49: }
50: // Copy the rest of the left side of the array into the target array
51: while (i <= middle) {
52: numbers[k] = helper[i];
53: k++;
54: i++;
55: }
56: }
57: }
Pronto, conseguimos !! Vamos entender agora como o programa Java implementa o algoritmo.
Classe MergeSort
Essa classe possui os métodos de ordenação e os atributos numbers, helper e number os quais representam respectivamente, o array de valores, o array auxiliar e a variável usada para armazenar o tamanho do array de valores.
Esta implementação já possui uma otimização implementada para o problema de memória citado acima. Da forma que foi projetado, o array auxiliar só é carregado uma vez em memória visando aliviar o consumo.
Método sort
Esse método recebe o array original e realiza as seguintes operações:
- Linha 8: passa os valores do array, recebido como parâmetro, para o array atributo, numbers.
- Linha 9: Define o valor do atributo number onde, esse valor é o tamanho do array original.
- Linha 10: Define a dimensão do array auxiliar onde, essa dimensão é a mesma do array original.
- Linha 11: Realiza a chamada ao método mergeSort, passando como parâmetros o número 0 e o resultado da operação number - 1 onde, zero representa o início de qualquer array e number - 1 representa a última posição do array.
Método mergeSort
Esse método realiza a divisão já citada acima. Recebe dois parâmetros: a posição inicial e final do array.
- Linha 16: Verifico se o parâmetro begin é menor que o parâmetro end. Essa verificação é necessária pois, ela realiza o controle da divisão do array. Caso a condição não seja verdadeira é porque o array está vazio ou, já está ordenado.
- Linha 18: Calculo o meio do array visando a divisão do mesmo.
- Linha 20: Realizo chamada recursiva passando como parâmetros begin e middle, ou seja, estou analisando a primeira metade do array dividido. Como esta é uma chamada recursiva, as linhas anteriores (16 e 18) serão executadas novamente, até o momento em que reste somente uma posição no array dividido n-vezes.
- Linha 22: Realizo chamada recursiva passando como parâmetros middle +1 e end, ou seja, estou analisando a segunda metade do array dividido. O processo de divisão segue de forma igual ao citado acima.
- Linha 24: Realizo chamada ao método merge passando os parâmetros: begin, end e middle. Dependendo do nível de recursividade da execução do algoritmo, os valores dessas variáveis não estarão iguais as que estavam originalmente.
Método merge
Esse método realiza a ordenação. Recebe três parâmetros: a posição inicial, final e média do array.
- Linha 31 até 33: Copia os valores do array original para o array auxiliar. Os valores copiados são limitados pelo intervalo definido pelas variáveis begin e end.
- Linha 35 até 37: Declaro as variáveis i, j e k.
- Linha 40 até 49: É aqui aonde a mágica acontece. A condição definido no loop while da linha 40 define que a iteração será feita do início da fatia esquerda até seu fim e depois do início da parte direita até seu fim. Essa condição é definida dessa forma porque sempre comparamos o grupo da esquerda com o da direita. Na imagem ou no gif animado é possível notar isso. Nas linhas 41 e 44, é avaliado quem é menor valor. Caso o valor da esquerda seja o menor, ele é copiado para o array original na posição certa (k) e a variável i é incrementada, caso contrário, o valor da direita é copiado e a variável j é incrementada. A variável k é incrementada fora do bloco condicional if pois, ele representa a posição final do valor ordenado logo, ele não precisa estar sendo incrementado onde é avaliado o menor valor e sim, depois que isso foi feito.
- Linha 51 até 55: Nesse bloco são copiados os valores restantes da ordenação. O bloco acima não deixa o array original totalmente ordenado, ele só passa os menores valores para frente (ordenação crescente). Então, precisamos de uma outra iteração para recuperar os outros valores do array auxiliar e posicioná-los nas posições corretas. Como sabemos quais as posições corretas ? A variável k não é zerada logo, ele ainda guarda referência do último valor ordenado posicionado. As variáveis i e k devem ser incrementadas para realização do posicionamento.
Cumprimos mais uma etapa do nosso estudo. Entendemos a implementação do nosso programa. Vamos realizar alguns testes ?
Nossos testes serão feitos da seguinte forma: iremos montar um array um valores aleatórios e com as dimensões da primeira coluna. Depois de montado, iremos realizar a operação de ordenação 1 milhão de vezes e medir o tempo total. O tempo individual de cada processamento é calculado pela divisão do tempo total por 1 milhão.
Figura 4 - Testes feitos para medir a execução do algoritmo |
Figura 5 - Gráfico de quantidade de elementos por tempo |
Para fazer o download do algoritmo, clique aqui.
Dúvidas !? Sugestões ?! Críticas ou elogios ?!
Deixe aí nos comentários ou na nossa página do facebook.
Referências:
Merge sort - https://pt.wikipedia.org/wiki/Merge_sort
John von Neumann - https://pt.wikipedia.org/wiki/John_von_Neumann
Gif Merge Sort - https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif
Program: Implement merge sort in java. - http://java2novice.com/java-sorting-algorithms/merge-sort/
Mergesort in Java - Tutorial - http://www.vogella.com/tutorials/JavaAlgorithmsMergesort/article.html
Estruturas de dados e algoritmos em Java, Robert Lafore, 2004
2 comentários:
Your blog has best article on sorting algorithm. Thanks for sharing.
Cheers,
http://www.flowerbrackets.com/java-merge-sort/
Thank you very much my friend.
Postar um comentário