Escolar Documentos
Profissional Documentos
Cultura Documentos
Paulo Lacerda
2 ALGORITMOS DE ORDENAÇÃO
Imagine que você precisa procurar por um nome em uma agenda de telefones sem
qualquer tipo de ordenação. Esta certamente seria uma tarefa complexa e demorada.
Esse mesmo problema ocorre com as informações em computação. Por esta razão,
sistemas que estruturam dados mais complexos com arrays e listas precisam
armazenar seu conteúdo em ordem crescente ou decrescente para facilitar as
pesquisas de informações dentro dessas estruturas.
20
Em termos de complexidade, as informações fundamentais são:
O algoritmo de ordenação por bolha opera de maneira simples. Ele percorre toda a
estrutura de dados (array) ou objeto a ser ordenado e faz uma comparação entre os
elementos adjacentes ou suas chaves verificando se estão na ordem correta. Essa
comparação pode ser realizada em ordem crescente ou decrescente (NASCIMENTO;
MOZZAQUATRO; ANTONIAZZI, 2016).
A cada iteração, o método de ordenação por bolha fica mais eficiente. Essas iterações
ocorrem por meio de um conjunto de comparações n-j, onde n é o número de
elementos e j é a contagem da iteração atual.
A respeito de complexidade, esse método tem seu pior caso em O(n²) e seu melhor
caso quando o algoritmo executa n operações relevantes, sendo n o número de
ordenações.
21
Fonte: O autor, 2019.
É importante lembrar que existe a necessidade de converter o array para string senão
haverá, somente, a visualização de um número do objeto criado em memória, algo
parecido com ‘[I@1e643faf’. Isso pode ser feito por meio do método Arrays.toString().
Observa-se que, entre as linhas 17 e 20, os valores e chaves são comparados e, caso
necessário, alterados de posição de forma a criar uma ordenação crescente dos
elementos. Na linha 24, o array é retornado em ordem.
22
Esse algoritmo tem a vantagem de ser fácil de compreensão e conhecido. Além disso, a
troca dos elementos de lugar é feita sem a necessidade de armazenamento
temporário, fazendo com que seu uso de memória seja mínimo. Apresenta,
entretanto, como principal desvantagem a baixa eficiência em organizar listas de
dados muito extensas.
2.1.2 Complexidade
Quando lidamos com listas muito longas, a quantidade de etapas faz com que esse
método se torne impraticável no mundo real. Por esta razão, esse algoritmo só é
usado no mundo acadêmico para gerar conhecimento de lógica de ordenação.
23
Essa mesma ideia pode ser traduzida para a lógica das máquinas por meio do
algoritmo de ordenação por inserção. O algoritmo percorre todo array, começando
pelo índice um, fazendo as comparações necessárias até posicionar o elemento no
local correto, ou seja, para cada iteração x do algoritmo, o elemento A[x] troca de
posição com cada elemento maior que ele a sua esquerda.
2.2.1 Complexidade
No melhor dos casos, a complexidade desse algoritmo é dada pelo termo O(n) quando
o array está completamente ordenado. Na pior das situações, tem-se o termo O(n²),
ou seja, um array com 20 elementos cria uma complexidade de 20², portanto 400
iterações.
24
2.2.2 Análise do algoritmo
O método de ordenação tem início na linha nove com a declaração de duas variáveis:
25
Uma vantagem do algoritmo de ordenação por inserção é que nenhum movimento e
realizado sem necessidade, pois a ordenação só ocorre quando algo está fora do lugar.
O algoritmo percorre a matriz várias vezes (figura 2.4), selecionando o menor próximo
item e posicionando-o no local correto, ou seja, funciona seguindo os seguintes
passos:
26
Em seguida, é feita uma busca para encontrar o menor elemento da matriz, neste
caso, é o número um. Se o valor do menor elemento for inferior ao do elemento
primeiro, ocorre uma troca. Caso contrário, as posições se mantém.
Fonte: O autor,2019.
2.3.1 Complexidade
Esse algoritmo também possui uma complexidade quadrática, ou seja, usa o termo
O(n2). Como, em cada iteração, ele compara um elemento a todos os outros, não
existe melhor ou pior caso, afinal, mesmo que o array esteja perfeitamente ordenado,
o algoritmo será executado do começo ao fim.
27
Fonte: O autor, 2019.
• Simplicidade de implementação;
• Não utiliza vetores auxiliares de armazenamento temporário, por isso não
ocupa muito espaço memoria;
• Possui velocidade para algoritmo de ordenação para estruturas pequenas.
A figura 2.8 mostra um script em linguagem Java implementado com o algoritmo por
seleção em uma estrutura de dados tipo array composta por 10 elementos não
ordenados do tipo inteiro.
28
Fonte: O autor, 2019.
29
Podem ocorrer variações no script como posicionar o número maior no final da matriz
ao invés do menor no início, entretanto elas não alteram a maneira básica como o
elemento mínimo (ou máximo) é encontrado e nem melhoram a eficiência do
algoritmo.
O algoritmo de ordenação por pente (combo sort) opera na base de troca de posições
exatamente como o algoritmo por bolha (bubble sort), entretanto realiza a operação
de maneira melhorada, pois processa os dados previamente. Sua principal função é
organizar estruturas de dados como listas e arrays (ELKAHLOUT; MAGHARI, 2017).
Uma comparação dos elementos é realizada por passos de posições distanciadas umas
das outras. A esses espaços é dado o nome de GAP (figura 2.9). Em cada iteração, esse
passo se torna menor até se igualar a um. O princípio do algoritmo é que os elementos
maiores sejam movidos na direção do final da matriz para evitar as chamadas
tartarugas (valores pequenos no final do array) que prejudicam o desempenho do
algoritmo de bolha.
Desta forma, pode-se dizer que, enquanto o GAP do algoritmo de bolha é sempre 1, o
de pente apresenta uma variação que tem início em X e termina em 1.
30
GAP = 3/1,3 = 2,3 = 2.
A cada iteração, os valores das extremidades do GAP são comparados. Se o valor inicial
for menor que o final, eles são trocados. Caso contrário são mantidos. O GAP se
desloca, casa por casa, para a direita até o final da estrutura (figura 2.11).
31
2.4.1 Complexidade
No melhor dos cenários, quando a matriz já está perfeitamente ordenada e não são
necessárias alterações, a complexidade da ordenação por pente é de O(n), por outro
lado, no pior dos casos ela é de O(n²).
Ensaios experimentais indicam que o desempenho da ordenação por pente pode ser
comparado ao Quick Sort que é considerado o algoritmo de ordenação mais rápido
disponível.
Na figura 2.12, podemos ver um script em linguagem Java que implementa o algoritmo
de ordenação por pente para organizar uma estrutura de dados tipo array. Por meio
de sua análise, seremos mais capazes de compreender a aplicação do algoritmo.
Nota-se que o fator de encolhimento foi usado para determinar o tamanho do GAP no
laço mais externo. Já no laço mais interno, foi empregado para fazer uma comparação
de elementos por meio de comando ‘compareTo’. Na linha 25 é incrementada a
iteração e na linha 28 é determinado que, após a ordenação, o array retorna para ser
exibido na linha 35 do código.
O algoritmo do tipo coquetel recebeu esse nome porque percorre a matriz de um lado
para o outro como se a estivessem chacoalhando. É similar ao sistema de ordenação
por bolha, afinal, ambos pertencem à família de algoritmos baseados em comparação.
A principal diferença entre esses dois sistemas é a maneira como eles percorrem a
estrutura dos dados. Enquanto o algoritmo por bolha se movimenta da esquerda para
a direita, o coquetel percorre ambas as direções (ELKAHLOUT; MAGHARI, 2017) o que
faz com que a sua implementação seja muito mais difícil (DEITEL; DEITEL, 2010) (figura
2.13)
33
O algoritmo de coquetel, em sua primeira iteração, envia o maior elemento para o
final da lista. Na segunda, transporta o menor valor para o início da matriz e continua
intercalando até o array estar completamente ordenado.
Fonte: O autor,2019.
Fonte: O autor,2019.
2.5.1 Complexidade
Esse algoritmo de ordenação pode ser aplicado em estruturas de dados como arrays e
listas. O seu nível de complexidade é de O(n2) no pior dos casos e O(n) no melhor dos
cenários.
34
2.5.2 Análise do código
O método cocktailSort tem início na linha sete com o recebimento do parâmetro que,
neste caso é o array de inteiros não ordenado. Nas linhas nove e dez, são declaradas as
variáveis de controles. Logo em seguida, um primeiro comando de repetição é usado
para fazer a análise da variável de troca e se a variável de início é menor que a do fim.
Dentro desse laço, existem dois comandos de repetição.
35
No primeiro, é feita uma comparação entre os elementos para entender qual é o maior
valor entre os pares e para posicioná-lo no final da matriz. No segundo, é feito um
contraste entre os pares para analisar qual é o elemento de menor valor para, então,
movê-lo para o início do conjunto. Esse processo se repete até que a condição inicial
do primeiro laço não seja satisfeita. Na linha 27, o array já ordenado retorna impresso
na linha 33.
Embora o algoritmo coquetel seja ligeiramente mais eficiente que o algoritmo por
bolha, é quase sempre mais lento que o de inserção. Desta forma não é muito
adequado para o uso em produção.
Conclusão
REFERÊNCIAS
DEITEL, P.; DEITEL, H. Java: como programar. 8. ed. São Paulo: Pearson, 2010. Cap. 9
36