Você está na página 1de 10

Análise do código

Agora, vamos ilustrar na prática o uso do algoritmo de ordenação de contagem


por meio da sua implementação na linguagem Java, ordenando uma estrutura de
dados array de nove elementos do tipo inteiro.

Figura– Algoritmo de ordenação Heap

Esse código é composto de quatro métodos. O primeiro é responsável por


determinar o elemento de heap e estabelecer o segundo método
(heapify_elementos()) que designa a estrutura de comparação para posicionar os
elementos à esquerda e à direita. O terceiro é responsável pelas trocas (swap()) e o
quarto ordena a estrutura sort().
Todas as variáveis passam pelo método principal (main()). Na linha 31 é feita a
declaração da matriz; na linha 32 o método de heapSort() é declarado. Por fim, os
valores ordenados são exibidos no console na linha 33.
Complexidade
Apesar de fazer muitas trocas, o método heap não é ineficiente, pois seu
esforço está concentrado em movimentar o maior elemento para a esquerda, técnica
que proporciona melhor desempenho. Sua complexidade é O(n log n) tanto no pior
quanto no melhor caso.

Quick sort
Como já visto anteriormente, o método de ordenação Shell é um dos que
apresenta maior viabilidade, pois tem como princípio básico dividir a matriz principal
em submatrizes menores e organizá-las individualmente. Em seguida, subdividindo
mais uma vez e repetindo o processo até que a matriz esteja completamente ordenada
(DEITEL; DEITEL, 2010).
Esse mesmo princípio é aplicado no método quick sort, afinal ele também divide
a matriz em partes menores para que a ordenação possa acontecer de forma rápida
e fácil (AREMU et al., 2013). O processo ocorre da seguinte maneira:
Primeiramente, é determinado um elemento de referência que será chamado
de pivô, chave ou limite. Em seguida, a matriz principal é dividida em duas. A primeira
é composta por elementos menores ou iguais ao pivô. A segunda por outro lado,
insere os elementos maiores ou iguais ao elemento limite.
A ordenação das matrizes primeira e segunda podem ser feitas
separadamente, porém, antes, é feita uma repetição de divisão para ambas as
matrizes. Esse processo acontece até que reste somente matrizes de um único valor
a ser ordenado.
Figura – Pivô

O conceito de recursividade é aplicado pelo algoritmo de ordenação rápido,


pois é feito algum tipo de divisão em cada etapa do processo.
Para que ocorra o particionamento da matriz, duas etapas devem ser
cumpridas. A determinação do pivô e o percorrer da matriz para posicionar os
elementos da submatriz.
As matrizes devem ser basicamente do mesmo tamanho, ou seja, uma
estrutura de duzentos elementos, idealmente, deve se dividir em duas de cem. Se
uma das duas submatrizes tiver quarenta elementos e a outra 160, ocorrerá um
desbalanceamento.
Por esta razão, a escolha do pivô é uma tarefa árdua e complexa.

Existem diversas formas de selecionar o limite da matriz. Uma das mais


funcionais e cuidadosa é encontrar elemento que está no meio da estrutura de dados
tipo array. Caso um ou mais elementos tenham o mesmo valor que este pivô, são
posicionadas a mesma quantidade de elementos em cada lado do elemento limite
para melhor satisfazer o balanceamento da matriz.
O esquema a seguir demonstra o particionamento de uma matriz de dez
elementos do tipo inteiro. A partir daí os menores elementos são movidos para a direita
enquanto os maiores são movidos para a esquerda. Desta maneira, não existe a
necessidade de comparar os elementos da submatriz esquerda com os da direita,
limitando as comparações para valores dentro da mesma matriz.

A) Declaração da Matriz
8 5 4 7 6 1 9 3 2 12 10

B) Escolha do pivô
8 5 4 7 6 1 9 3 2 12 10

C) Deslocamento dos menores elementos para a esquerda e dos maiores


para a direita
5 4 1 3 2 6 8 7 9 12 10

D) Escolha de um novo pivô na matriz de valores mais baixos e


deslocamento dos elementos menores para a sua esquerda e dos maiores
para sua a direita.

Neste exemplo, todos os elementos ficaram do lado direito do pivô, pois ele
tinha o menor valor da matriz.

E) Escolha do novo pivô.


F) Escolha de mais um pivô

Observe que o lado esquerdo da matriz está perfeitamente ordenado. Por conta
disso o processo vai se repetir, desta vez, aplicado à submatriz direita.
É importante entender o algoritmo de ordenação rápida apresenta eficiência
muito baixa na ordenação de matrizes com menos de trinta elementos. Nestes casos,
o uso de um algoritmo de organização por inserção é muito mais recomendado.

Análise do algoritmo
Agora, vamos ilustrar na prática o uso do algoritmo de ordenação rápido por
meio da sua implementação na linguagem Java, ordenando uma estrutura de dados
tipo array de nove elementos do tipo inteiro.
Algoritmo de ordenação rápida
Verifica-se que o algoritmo cria o objeto na linha 26; declara a matriz na linha
27; determina o método ordena() na linha 28; e define a rotina de exibição do método
ordenado na linha 29. Assim, por meio dessas quatro linhas, é declarado o método
principal.
Já o método de ordenação tem início na linha oito. A princípio, averigua-se se
o array não é nulo ou igual a zero. Em seguida, o seu tamanho é verificado e o método
de ordenação sort() é declarado na linha 11.
Na linha 12, o método quicksort() recebe dois parâmetros que são os limites
inferior e superior da estrutura. Esse método possui três comandos de repetição para
determinar a varredura do array, os elementos maiores e os menores das duas
submatrizes.
Na linha 23, os elementos do array são trocados, esse método, dentro do
comando, recebe o nome de decisão. Na linha 17 é inserido um comando de repetição
da linha 16. Por fim, a recursividade é implementada nas linhas vinte e 22.
Complexidade
O algoritmo de ordenação rápida, certamente, é um dos que possui melhor
desempenho, desde que o pivô escolhido seja um elemento mediano da matriz. A sua
complexidade, no melhor dos casos, é representada pelo termo O(n log n) e, no pior,
O(n²).

Merge sort
Embora o algoritmo de ordenação rápida seja eficiente, o seu pior caso pode
resultar em certa dificuldade de controle do processo de particionamento. Isso
acontece porque os procedimentos de divisão não garantem que as submatrizes
serão iguais em termo de tamanho. Por esta razão, se fazem necessárias estratégias
diferentes que auxiliem a localização do pivô para padronizar a execução desse
processo regular.
Uma estratégia de particionamento é fazer a fusão das duas matrizes
ordenadas na tentativa de tornar o processo tão simples quanto possível. Esse
princípio é a base do algoritmo de ordenação por fusão (merge) (QIN, 2014).
Esse método consiste em dividir a matriz e aplicar o conceito de recursividade
para ordenar as submatrizes decorrentes e, logo em seguida, fundi-las novamente.
Costuma ser aplicado em estruturas de dados array e listas encadeadas.
O fato do algoritmo de ordenação por fusão usar a técnica da recursividade
resulta em um alto consumo de memória e tempo de execução, pois, a cada nível de
recursividade, uma cópia da matriz é criada e posicionada na memória.
Com base nos princípios de divisão, conquista e fusão, a figura ilustra o
funcionamento do algoritmo por fusão no processo de ordenação de uma estrutura.
Primeiramente, a matriz é repartida o maior número de vezes possível. Esse
processo é feito com auxílio da técnica da recursividade. Em seguida, cada submatriz
é organizada individualmente. Por fim, é feita a fusão das partes e ordenação da
estrutura.
Figura– Conceito do método merge sort

O algoritmo por fusão pode apresentar maior eficiência se passar por algumas
adaptações. Na fase da divisão, pode-se substituir a técnica da recursividade pela
iteração. Na fase da conquista, é possível combinar o merge sort com outros
algoritmos. Desta forma, em algoritmos menores, pode-se empregar o algoritmo de
ordenação por inserção.

Análise do algoritmo

Agora, vamos ilustrar na prática o uso do algoritmo de ordenação por fusão por
meio da sua implementação na linguagem Java, ordenando uma estrutura de dados
tipo array de nove elementos do tipo inteiro.

Figura– Algoritmo de ordenação por fusão

Observa-se que, na linha sete, uma matriz não ordenada de nove elementos é
declarada. O método de ordenação e exibição da matriz no console após aplicação
do algoritmo de ordenação por fusão é definido na linha oito.
O método de ordenação mergeSort() usa o recurso de comparação
(Comparable) e recebe como parâmetro a matriz input não ordenada. Nas linhas 12 e
13 são especificados os tamanhos (limites) das submatrizes.
As fases de divisão, cópia e fusão são descritas nas linhas de 14 a 18. A técnica
de recursividade é aplicada nas linhas 16 e 17. O método de fusão é declarado nas
linhas de 21 a 33. Essa fase pode ter um alto custo de processamento para o
algoritmo.

Complexidade

A complexidade do algoritmo de ordenação por fusão pode ser definida pelo


termo O(n log n), tanto no melhor, quanto no pior caso.

Você também pode gostar