Tema 5 - Ordenação
Tema 5 - Ordenação
Tema 5 - Ordenação
PROPÓSITO
Algoritmos de ordenação de uma sequência de chaves é, sem dúvida, um dos problemas mais
estudados em computação. Obter conhecimento sobre os algoritmos de ordenação
elementares permitirá que você consiga escolher o método de ordenação mais adequado ao
problema a ser solucionado, para que possa desenvolver um algoritmo que seja eficiente e
rápido.
OBJETIVOS
MÓDULO 1
MÓDULO 2
ORDENAÇÃO
O problema da ordenação é, sem dúvida, um dos mais antigos e mais estudados em
computação. É a ferramenta para a solução de diversos problemas mais complexos e existem
diversos algoritmos que resolvem este problema.
Informalmente, podemos enunciar o problema como sendo encontrar uma permutação de uma
sequência de dados, tal que dois elementos adjacentes desta sequência satisfaçam a uma das
relações a seguir:
Uma instância do problema é composta por um conjunto de dados em uma sequência arbitrária
de tamanho n e sua solução é a permutação que respeite a relação de ordem desejada.
EXEMPLO
Por exemplo, a sequência 12, 35, 17, 92, 45, 8 é uma instância de tamanho n = 6 e a solução
desta instância é a permutação 8, 12, 17, 35, 45, 92, se a relação de ordenação for menor que
(“<”), ou a permutação 92, 45, 35, 17, 12, 8, se a relação de ordenação for maior que (“>”).
Seja S =s1, s2, s3, ...., sn uma sequência de números inteiros distintos. Ordenar a sequência S
é equivalente a encontrar a permutação S’ =s’1, s’2, s’3, ... , s’n tal que s’i < s’i+1 para 0 < i < n.
EXEMPLO
Por exemplo, caso os objetos de dados fossem cadeias de caracteres, poderíamos definir a
relação “<” como a ordem lexicográfica (“ordem alfabética”), viabilizando o processo de
ordenação. Assim, por exemplo, a cadeia “Andrea” < “Luiz”.
Definido o problema, pode-se dizer que um algoritmo de ordenação é a entidade que recebe
como entrada uma instância do problema de ordenação e fornece como saída uma permutação
desta entrada, satisfazendo a relação de ordem definida no enunciado do problema.
Complexidade computacional.
Complexidade de espaço.
Caráter recursivo.
Estabilidade.
COMPLEXIDADE COMPUTACIONAL
O(1)
O(log n)
O(n)
O(n log n)
O (n 2 )
A frieza da Matemática não traduz com precisão a separação existente nesta classificação.
Para exemplificar, vamos comparar uma busca linear em um vetor, que procura por todos os
elementos do vetor, com a busca binária.
A ideia básica do algoritmo de busca binária é simples. Seja V um vetor ordenado. A busca
binária compara a chave buscada com o elemento central do vetor (n/2, onde n é o tamanho do
vetor). Caso a chave seja igual ao elemento buscado, temos o sucesso, caso contrário, a chave
buscada pode ser maior ou menor. Conforme o caso, buscamos recursivamente na metade
superior ou inferior do vetor.
Imaginemos agora que desejamos buscar uma chave em um vetor de 106 elementos. Com a
busca linear, teríamos que realizar 106 comparações. Aplicando a busca binária, teremos log2
106 ≅20 comparações. Isto é a mudança na classificação de ordem e implica numa mudança
significativa na quantidade de operações elementares executadas.
Sendo assim, os algoritmos mais eficientes de ordenação geram árvores de decisão de altura
mínima, isto é, árvores completas. Ou seja, se determinarmos a altura da árvore de decisão
mínima (árvore completa), determinamos a quantidade mínima de comparações para ordenar
um vetor.
Como a árvore é completa com n! folhas, sabe-se que esta árvore possui 2(n!) nós, porém
2(n!) < nn. Sabemos também que a altura da árvore completa é proporcional a log k, onde k é
o número de nós da árvore. Logo, a altura da árvore de decisão é menor que log (nn) = n log
n, o que mostra o resultado.
COMPLEXIDADE DE ESPAÇO
1 Para i = 1 até n
2 aux [V[i]]=1;
Após esta operação, percorremos o vetor auxiliar, colocando em V os valores do índice que
não possuem valor zero.
1 j=0;
2 para i = 0 ate 100000
3 se (aux[i] == 1)
4 inicio
5 V[j]=i;
5 j++;
7 fim
Observe que a análise de complexidade de tempo para este caso é tendenciosa. Isto é,
despreza o fato de que a memória precisa ser inicializada e este passo consome recursos
computacionais. Algoritmos cuja linearidade não é proporcional ao tamanho da instância, e sim
ao tamanho do conjunto universo são chamados de algoritmos pseudolineares e, normalmente,
possuem complexidade computacional alta.
Esta característica refere-se ao local onde os dados estão armazenados. Como sabemos, todo
computador tem a memória principal ou memória RAM e a memória secundária, no caso, disco
rígido ou memória de estado sólido.
A forma de acesso.
A velocidade de acesso.
Em relação à velocidade, a memória principal é muito mais rápida que a secundária. O tempo
ATENÇÃO
Vale destacar que os algoritmos de ordenação externa não são capazes de abstrair
completamente a memória principal, isto é uma impossibilidade no paradigma de von
Neumann. Para a execução de um programa, o código e os dados devem estar em memória
principal. Assim sendo, um algoritmo de ordenação externa copia parte dos dados para a
memória principal, trata estes dados e armazena o resultado (a sequência ordenada) em
memória secundária.
CARÁTER RECURSIVO
Outra característica dos algoritmos de ordenação é o caráter recursivo. Alguns algoritmos são
recursivos, normalmente aplicando a estratégia dividir para conquistar. Outros são sequenciais.
Em particular, este algoritmo é baseado na comparação entre dois elemento do vetor, isto é
feito no passo de concatenação e, por isso, o algoritmo não pode ter complexidade inferior a
O(n log n). A complexidade deste algoritmo é, de fato, O(n log n). Para realizar a análise, não
é necessário estudar o código do algoritmo. A Figura 2 é um bom instrumento de análise.
Na Figura 2, cada linha representa a divisão do vetor em duas metades e de suas metades
recursivamente (daí o caráter recursivo do algoritmo). Vejamos quantas linhas temos até a linha
dos problemas infantis.
.....
Porém, sabemos que na linha k os problemas são de tamanho = 1, assim 1 = n/2k-1, logo n =
2k-1. Aplicando log2 temos log2 n = log2 2k-1, que fornece k-1 = log2 n, k = log2 n + 1
ESTABILIDADE
Diz-se que um algoritmo de ordenação é estável quando elementos que são apresentados já
na ordem correta são mantidos durante a execução do algoritmo. Assim, se for apresentada
uma sequência já ordenada para um algoritmo estável, o algoritmo não irá realizar nenhuma
operação de troca.
Um efeito da estabilidade é a possível redução do número de operações elementares
necessárias para execução do algoritmo. Porém, o efeito da estabilidade é percebido nas
instâncias com os melhores casos e não nos piores casos. Assim, a estabilidade do algoritmo
não tem impacto na complexidade computacional teórica.
Para estes algoritmos, o teorema que determina o limite inferior da ordenação como O(n log n)
não se aplica, uma vez que sua premissa é invalidada, isto é, a árvore de decisão não é
“montada” pelo algoritmo. Portanto, é teoricamente possível existirem algoritmos de ordenação
desta classe que possuem complexidade inferior a O(n log n).
EXEMPLO
ETAPA 01
ETAPA 02
ETAPA 03
ETAPA 01
Centena 1: -
Centena 3: -
Centena 5: -
Centena 6: -
Centena 7: -
Centena 8: 890
Centena 9: -
ETAPA 02
Centena 0:
Dezena 0: 005
Dezena 1: 014
Centena 2:
Centena 4:
Dezena 2: 423
Dezena 5: 456
Centena 8:
Dezena 9: 890
ETAPA 03
Centena 0:
Dezena 0:
Unidade 5: 005
Dezena 1:
Unidade 4: 014
Centena 2:
Dezena 3:
Unidade 5: 235
Unidade 6: 236
Centena 4:
Dezena 2:
Unidade 3: 423
Dezena 5:
Unidade 6: 456
Centena 8:
Dezena 9:
Unidade 0: 890
Concatenando tudo na ordem (de cima para baixo): 005, 014, 235, 236, 423, 456, 890.
Alguns autores citam a complexidade deste algoritmo como O(n). A argumentação é que, como
a quantidade de dígitos k é conhecida e constante, e para cada ordem numérica percorremos a
sequência a ser ordenada uma vez, temos k * n que representa uma complexidade de O(n).
VERIFICANDO O APRENDIZADO
MÓDULO 2
EXEMPLO
Por exemplo, para a sequência S = s1 = 10, s2 = 12, s3 = 15, s4 = 20, s5 = 25, temos que s1 <
s2, s2 < s3, s4 < s5. Por esta razão, podemos afirmar que a sequência está ordenada.
A ideia do método da bolha é explorar esta propriedade com o objetivo de ordenar o vetor.
EXEMPLO
No exemplo acima, S = s1 = 10, s2 = 12, s3 = 15, s4 = 20, s5 = 25, realizamos uma iteração, ou
seja, todas as comparações, e verificamos que a propriedade é válida para todo par de
elementos adjacentes. Isto garante a ordenação da sequência. De fato, se si < si+1 e si+1 <
si+2 então si < si+2, ou seja, a comparação é transitiva e assim se garante que a relação é
O método da bolha explora esta propriedade realizando a troca de posição caso a comparação
entre elementos adjacentes falhe.
MÃO NA MASSA
Vejamos um exemplo, seja a sequência S = 15, 20, 8, 16, 40. No ábaco abaixo, vamos
destacar o par que está sendo comparado a cada passo. Caso a comparação seja bem-
sucedida, isto é, si < si+1, nada é realizado, caso contrário, efetuamos a troca.
Na iteração completa que não ocorra troca, teremos a sequência ordenada.
ETAPA 01
ETAPA 02
ETAPA 03
ETAPA 01
Início da 1ª iteração
Fim da 1ª iteração
ETAPA 02
Início da 2ª iteração
Fim da 2ª iteração
ETAPA 03
Início da 3ª iteração
Passo 1: 8 < 15, 16, 20, 40
Outra característica interessante é que, em uma iteração, o valor que é trocado vai para a
posição dele no vetor ordenado. Isto é, na primeira iteração, o maior valor vai para última
posição, na segunda iteração, o segundo maior valor vai para penúltima posição, e assim,
sucessivamente. Deste modo, o pior caso para o método da bolha é quando apresentamos a
sequência ordenada em ordem reversa na entrada do algoritmo.
Para fins de análise, seja a sequência S = s1 < s2 < s3 < ... < sn. Se ela for apresentada em
ordem reversa para o algoritmo da bolha, teremos na entrada S’ = sn, ..., s3, s2, s1. Assim, a
1ª iteração: sn-1, sn-2, ..., s3, s2, s1, sn – após n-1 comparações e trocas
2ª iteração: sn-2, ..., s3, s2, s1, sn-1, sn – após n-1 comparações e trocas
n-2ª iteração: s2, s1, s3, ..., sn-2, sn-1, sn – após n-1 comparações e trocas
n-1ª iteração: s1, s2, s3, ..., sn-2, sn-1, sn – após n-1 comparações e nenhuma troca
ocorre. Assim, para ordenar o vetor, o algoritmo executa (n-1)2 comparações, isto é, o algoritmo
O algoritmo é iterativo e parte do princípio que a sequência não está ordenada e que todos os
elementos da sequência estão fora de sua posição.
Na primeira iteração, o algoritmo analisa a sequência S = s1, s2, ..., sn e determina o menor
elemento desta sequência. Seja sk = s’1 este elemento. Em seguida, o algoritmo troca s’1 com
Na segunda iteração, como s’1 é o menor elemento, s’1 está na posição correta. Ou seja, s’1 é
o primeiro elemento da sequência ordenada. Nesta iteração, o algoritmo irá determinar o menor
elemento entre s2, ..., s1, ..., sn, que será o segundo menor elemento da sequência ordenada.
Seja sj o menor elemento entre s2, ..., s1, ..., sn, seja s’2 = sj. Trocando sj = s’2 com s2, temos
a sequência s’1, s’2, s3 ..., s1, ..., s2, ..., sn. Ao término da segunda iteração, s’1, s’2
Repetimos cada iteração n-1 vezes, assim teremos a sequência ordenada completando a
execução do algoritmo. Utilizando a sequência 13, 25, 8, 19, 7, 52 como exemplo, vamos
executar o algoritmo.
A complexidade computacional do algoritmo é O(n2). Este fato pode ser provado analisando o
número de iteração e a quantidade de operações por iteração. O primeiro passo para a análise
é determinar a operação fundamental do algoritmo. A cada iteração, necessitamos o valor
mínimo de uma sequência de n elementos. A operação básica para isto é a comparação.
...
Logo, o número de operações elementares é: n-1 + n-2 + ... + 1 = (n)(n-1)/2 que é O(n2). Um
aspecto relevante na análise de complexidade do método da seleção é que não existe um tipo
de instância de pior caso, para todas as instâncias o algoritmo executa de mesma forma em
O(n2).
O código acima apresenta a versão menos estável do algoritmo. Observe que trocamos o valor
armazenado na posição i do vetor com o menor valor da sequência i+1 até o tamanho do
vetor. Uma forma de fazer isto é trocar todo elemento v[j] < v[i], está conceitualmente correto,
porém reduz a estabilidade do algoritmo.
Os elementos já ordenados.
Os elementos a ordenar.
ETAPA 01
ETAPA 02
ETAPA 03
ETAPA 04
ETAPA 01
ETAPA 02
Na segunda iteração, vamos colocar o elemento “20” na posição correta que, por coincidência,
já está posicionado. Sendo assim, passamos a ter “8, 16, 20” como sequência ordenada e “18,
9, 2” como não ordenada.
ETAPA 03
Na quarta iteração, analisamos “9”, obtendo “8, 9, 16, 18, 20” e “2”.
A complexidade deste algoritmo também é O(n2). Assim como o método da bolha, o algoritmo
tem o pior caso bem formado, a saber, as instâncias ordenadas em ordem reversa da
desejada. Seja a sequência S = s1, s2, s3, ..., sn onde s1 < s2 < s3 < ... < sn. Supondo que
...
n-3ª iteração: s3, ..., sn-2, sn-1, sn, s2, s1 – n-3 trocas
n-2ª iteração: s2, s3, ..., sn-2, sn-1, sn, s1 – n-2 trocas
n-1ª iteração: s1, s2, s3, ..., sn-2, sn-1, sn – n-1 trocas
O(n2).
Assim como os outros, o algoritmo é estável, não recursivo e com complexidade de espaço de
O(n). O programa em Linguagem C que implementa o algoritmo é apresentado no Programa 4.
APLICANDO OS ALGORITMOS DE
ORDENAÇÃO.
Para acompanhar o vídeo, você pode baixar o código fonte do programa que será utilizado no
vídeo clicando aqui.
VERIFICANDO O APRENDIZADO
CONCLUSÃO
CONSIDERAÇÕES FINAIS
Neste tema, viajamos pelo mundo dos algoritmos de ordenação elementares. Inicialmente,
estudamos o problema da ordenação, como analisar e classificar os algoritmos de ordenação e
como as diversas métricas de classificação devem ser aplicadas para a escolha do algoritmo
de ordenação.
PODCAST
AVALIAÇÃO DO TEMA:
REFERÊNCIAS
FRIEND, E. Sorting on electronic computer systems. J. ACM 3 (1956), 134–168.
EXPLORE+
Para saber mais sobre os assuntos tratados neste tema, leia:
CONTEUDISTA
Luiz Henrique da Costa Araujo
CURRÍCULO LATTES