Você está na página 1de 25

Projeto e Análise de Algoritmos

Algoritmos de Ordenação

T1530A, T7043A

III. Algoritmos de Ordenação (Classificação)


Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Sumário
III.1. Introdução ........................................................................................................... 3
III.2. Ordenação por troca ........................................................................................... 4
III.2.1. Método da Bolha ( bubblesort) .................................................................... 4
III.2.2. Ordenação por troca de partição (QuickSort)............................................... 7
III.3. Ordenação por seleção..................................................................................... 10
III.3.1. Seleção direta............................................................................................. 11
III.4. Ordenação por inserção.................................................................................... 13
III.4.1. Inserção simples......................................................................................... 13
III.4.2. Ordenação de Shell (shellsort) ................................................................... 15
III.5. Ordenação em Árvore....................................................................................... 18
III.5.1. Ordenação por heapsort............................................................................. 18
III.6. Uma comparação superficial dos algoritmos de ordenação.............................. 23
III.7. Comentários Adicionais .................................................................................... 24
III.8. Bibliografia ........................................................................................................ 25
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

III.1. INTRODUÇÃO

A existência de vetores ordenados permite a utilização de algoritmos muito eficientes


para acelerar um processo de busca. Contudo, o uso de métodos de ordenação
também apresenta custos.

Relação Busca x Ordenação

Tempo - desempenho

Ordenação: O que considerar?


• tempo de codificação;
• tempo de execução;
• espaço requerido.

Perguntas a fazer:
• Vale a pena investir num algoritmo de ordenação muito eficiente? Se não, é
importante saber justificar o porque!

• Vale a pena implementar um algoritmo ineficaz, em um determinado trecho de


programa, para economizar tempo de desenvolvimento? Qual o
impacto no sistema como um todo?

Observação: Pode, às vezes, existir justificativa para o uso de um algoritmo


ineficiente, mas não há justificativa para um algoritmo incorreto!

Observação: Conhecer vários algoritmos e sua eficiência, vantagens e


desvantagens, é fundamental para o desenvolvimento de aplicações
com maior valor da relação desempenho/custo (menor custo e maior
desempenho).

Eficiência: Tempo - espaço

Algoritmos de classificação, em geral, são de O(N lnN) a O(N2), com respeito ao


tempo,e O(n) com respeito ao espaço.

Na maioria dos casos – tempo de ordenação é dependente da seqüência original


dos dados. Portanto conhecer a ordem, ou a seqüência, dos dados
originais de entrada auxilia na escolha do algoritmo.

Outro aspecto a considerar – eficiência da implementação x clareza de código.

página 3
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Se a ordenação afeta em muito o desempenho do sistema, a clareza pode ser


sacrificada.

Exemplos:

 • Bolha
– Classificação por troca: 
 • Quicksort - classifica ção por troca de partição

- Classificação por seleção

 • Binária
- Classificação em árvore: 
 • Heapsort

 •Inserção simples

- Classificação por inserção:  •Shell
 •Cálculo de endereço

- Classificação por intercalação

- Classificação por raiz

No restante desta apostila nós iremos apresentar alguns desses métodos de


ordenação e avaliar sua eficiência.

III.2. ORDENAÇÃO POR TROCA

Objetivo é varrer o vetor, trocando a posição de elementos que forem identificados


fora da ordem. O processo de varredura envolve a realização de comparações
sucessivas de pares de elementos.

III.2.1. Método da Bolha ( bubblesort)

Algoritmo básico:

1. Em cada passo, cada elemento é comparado ao próximo


2. Se o elemento estiver fora de ordem, é realizada a troca
3. realizam-se tantos passos quanto necessários, até que não ocorram mais trocas.

página 4
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Pseudocódigo:

constante
MAXIMO = 100 % pode ser um dado fornecido a uma rotina
variáveis
vetor[1... MAXIMO]: inteiro
j, i, trab, limite: inteiro
troca: lógico

inicio
para i ← 1 até MAXIMO faça
leia (vetor[i])
fim para

troca ← true;
limite ← MAXIMO – 1
enquanto (troca = true) faça
inicio
troca ← false
para i ← até limite faça
inicio
se vetor[i] > vetor [i + 1] então
trab ← vetor[i]
vetor[i] ← vetor[i + 1]
vetor[i + 1] ← trab
j← i
troca ← true
fim se
fim para
limite ← j
fim enquanto
fim

Exercício: Desenvolva uma função, em linguagem C, que implemente o


algoritmo descrito acima.

Exemplo:
25 57 48 37 12 92 86 33
1o 25 48 37 12 57 86 33 92 // maior valor está no final da seqüência
passo
2o. 25 37 12 48 57 33 86 92 // 2o. maior valor já está na posição
passo correta
3o. 25 12 37 48 33 57 86 92
passo

página 5
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

4o. 12 25 37 33 48 57 86 92
passo
5o. 12 25 33 37 48 27 86 92
passo
6o. Sem trocas
passo

Exercício: Comparar comportamento dos dois algoritmos.

Eficiência da Ordenação pelo Método da Bolha

O algoritmo utiliza duas estruturas de repetição aninhadas. Grosseiramente,


no laço interno são executadas, no máximo, N-1 comparações (na verdade menos,
visto que a variável limite é modificada).

Pior implementação – pior caso

n_comparações: (N-1)*(N-1) = N2 – 2N +1 ⇒ é O(n2)


n_médio de comparações = n_comparações/2

Observação: Provavelmente, o tempo de troca é maior que o tempo despendido


nas comparações (troca envolve, pelo menos, 3 atribuições). Esta
consideração modifica a avaliação feita acima apenas por um fator
multiplicativo.

Na melhor implementação (pior caso)

Numa iteração realizada com o laço externo, são efetuadas (N-passo-1)


comparações. Assim, para um número total de passo iterações, o número total de
iterações será:

64 4 4 k4termos
74 4 4 4 8
(N - 1) + (N + 2) + (N - 3) + ... + (N - k) = kN (1 + 2 + 3 + ... + (k - 1) + k)
k 
= kN -  (k + 1)
2 
(2kN - k 2 - k)
=
2
O número médio de iterações k depende de N, de sorte que k é O(N). Portanto, esta
modificação resulta em um algoritmo O(N2) também. O efeito das modificações é
reduzir o fator multiplicativo da definição de ordem O.

página 6
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

III.2.2. Ordenação por troca de partição (QuickSort)


Este método parte do princípio que é mais rápido ordenar dois vetores com n/2
elementos cada um, do que um com n elementos (conceito dividir para conquistar).

O primeiro passo é dividir o vetor original. Esse procedimento é denominado


particionamento. Primeiramente, deve-se escolher um dos elementos do vetor (por
exemplo, V[i]) o qual é denominado pivô. Uma vez escolhido o pivô, os elementos
do vetor são movimentados de forma que o subvetor à esquerda do pivô contenha
somente os elementos cujo valor é menor que o valor do pivô e o subvetor da direita
contenha valores maiores que o valor do pivô.

V[1], ..... V[i-1] V[i] V[i+1], ..... V[n]

O procedimento é repetido até que o vetor esteja ordenado.

Existem várias formas de escolher o pivô:


• partindo do primeiro elemento do vetor;
• por escolha aleatória;
• escolha da mediana dos valores da esquerda, da direita e do meio de cada
subvetor;
• escolha do valor do meio de um subvetor.

O algoritmo apresentado a seguir considera esta última opção, a qual resulta em um


algoritmo mais eficiente.

Algoritmo:
a) Pivô é escolhido no meio do vetor. O elemento é colocado numa variável
auxiliar trab;
b) São iniciados dois ponteiros i e j;
c) O vetor é percorrido a partir da esquerda até que se encontre um V[i] ≥ trab (i
é incrementado no processo);
d) O vetor é percorrido a partir da direita até que se encontre um V[j] ≤ trab (j é
decrementado no processo);
e) Os valores V[i] e V[j] são trocado; i é incrementado de 1 e j é decrementado
de 1;
f) O processo é repetido até que i e j se cruzem em algum ponto do vetor;
g) Quando são obtidos os dois segmentos do vetor por meio do processo de
partição, realiza-se a ordenação de cada um deles de forma recursiva.

página 7
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Pseudocódigo:
Função QuickSort (V[ ] : Vetor de inteiro, esquerda, direita : inteiro)
Inicio
variáveis
trab, aux : inteiro
i, j : inteiro
i ← esquerda
j ← direita
trab ← V[(esquerda + direita) div 2]
repita
enquanto trab > V[i] faça
P
inicio
i ← i + 1;
A
fim enquanto
R
enquanto trab < V[j] faça
inicio
T
j ← j - 1;
fim enquanto I
se i ≤ j então Ç
inicio
aux ← V[i] Ã
V[i] ← V[j]
V[j] ← aux O
i ← i+1
j ← j–1
fim se
até i > j

se esq < j então QuickSort (V, esquerda, j)

se dir > i então QuickSort (V, i,direita)

fim

Observem que a variável trab corresponde ao pivô.

Exercício: Tentem escrever um algoritmo para o quicksort sem


usar a recursividade.

Exercício: Implemente o algoritmo apresentado acima na


linguagem C.

Pergunta: Quais as vantagens e as desvantagens do uso de


recursividade?

página 8
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Exemplo:

V[ ] 25 57 48 37 12 92 86 33 esquerda = 1; direita = 8,
trab = V[4] = 37,
1o passo 25 33 12 37 48 92 86 57 Resultado obtido após a primeira
ordenação em torno do pivô
Partição 1 25 33 12 esquerda = 1, direita = 3, trab =
vetor da V[(1+3)/2] = V[2] = 33
esquerda
25 12 33 Resultado obtido após a reordenação
do vetor da direita (primeira partição)
Partição 2 25 12 esquerda = 1, direita = 2,
Vetor da trab = V[(1+2)/2] = V[1] = 25
esquerda
12 25
Partição 2 33 O processo recursivo é interrompido.
Vetor da
direita
Vetor da 12 25 33
Esquerda
reordenado
Partição 1 48 92 86 57 esquerda = 5, direita = 8
vetor da trab = V[(5+8)/2] = V[6] = 92
direita
48 57 86 92 Resultado obtido após a reordenação
do vetor da direita (primeira partição)
Partição 2 48 57 86 esquerda = 5, direita = 7
Vetor da trab = V[(5+7)/2] = V[6] = 57
direita
48 57 86 processo recursivo é interrompido
Vetor da 48 57 86 92
Direita
reordenado
Vetor 12 25 33 37 48 57 86 92
original
ordenado

página 9
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Eficiência da Ordenação pelo Método Quicksort

Para analisar a eficiência do quicksort vamos supor um vetor de n elementos, onde n


é uma potência de 2. Desta forma, n = 2m, o que implica que m = log2n.

Pergunta: porque fazer esta hipótese?

Para simplificar ainda mais a análise, vamos assumir que o pivô está sempre no
meio exato do subvetor.

Nestas condições ocorrem n-1 comparações na primeira passagem. Como a análise


sempre é feita pensando em problemas de tamanho grande (ou seja n grande)
vamos utilizar apenas o valor n. Após isso, o vetor é subdividido em em outros dois
vetores, cada um com tamanho n/2, aproximadamente. Para cada um desses
subvetores ocorrem, aproximadamente, n/2 comparações. em seguida ocorre nova
subdivisão de vetores. Neste ponto, temos 4 subvetores, cada um de tamanho n/4 e,
em cada um, são efetuadas n/4 comparações. Este processo continua por m vezes
(quando o processo recursivo é interrompido e o vetor está ordenado), resultando
em n subvetores de tamanho 1.

O número total de comparações para o ordenamento do vetor será dado,


aproximadamente, por:

64 4 4 4 4 4 4 4 4m termos 74 4 4 4 4 4 4 4 4 8
n + 2 * (n / 2) + 4 * (n / 4) + 8 * (n / 8) + ... + n * (n / n ) = n * m

Finalmente, podemos concluir que o número total de comparações é O(n*m) ou,


ainda, O(n * log(n)).

Pergunta: Isto é bom ou mau? Para responder, faça uma


comparação com a eficiência do método da bolha.

III.3. ORDENAÇÃO POR SELEÇÃO

O maior, ou menor, valor contido no vetor é selecionado e colocado diretamente na


posição correta (no vetor). O processo é repetido para o segmento do vetor que
contém os elementos não selecionados.

página 10
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

III.3.1. Seleção direta


Algoritmo básico

1. Identifica-se o menor (ou maior) elemento no segmento do vetor que contém


os elementos ainda não selecionados;
2. Troca-se o elemento identificado com o primeiro elemento do segmento;
3. Atualiza-se o tamanho do segmento (diminui uma posição);
4. Interrompe-se o processo quando o segmento contiver apenas um elemento.

Pseudo-código

constante:
TAMANHO = 15
variáveis:
vetor[1...TAMANHO]: inteiro
i, j, trab, menor: inteiro

início
para i ← 1 até TAMANHO faça
leia (vetor[i])
fim para
para i ← 1 até TAMANHO-1 faça
menor ← i
para j ← i + 1 até TAMANHO faça
se vetor[j] < vetor[menor] então
menor ← j
fim se
fim para
trab ← vetor[i]
vetor[i] ← vetor[menor]
vetor[menor] ← trab
fim para
fim

Exercício: Desenvolva uma função, em linguagem C, que implemente o


algoritmo descrito acima.

página 11
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Exemplo:

25 57 48 37 12 92 86 33
1o passo 25 57 48 37 12 92 86 33 // identifica menor valor do
segmento (segmento na cor cinza)
12 57 48 37 25 92 86 33 // troca-se a posição com o primeiro
elemento do segmento
2o. passo 12 57 48 37 25 92 86 33 // identifica menor valor do
segmento (tamanho do segmento
diminuiu de uma posição)
12 25 48 37 57 92 86 33
3o. passo 12 25 48 37 57 92 86 33
12 25 33 37 57 92 86 48
4o. passo 12 25 33 37 57 92 86 48
12 25 33 37 57 92 86 48
5o. passo 12 25 33 37 57 92 86 48
12 25 33 37 48 92 86 57
5o. passo 12 25 33 37 48 92 86 57
12 25 33 37 48 57 86 92
6o. passo 12 25 33 37 48 57 86 92
12 25 33 37 48 57 86 92
7o. passo 12 25 33 37 48 57 86 92 //fim do processo

Eficiência da Ordenação pelo Método de Seleção Direta

A análise deste algoritmo é bastante simples e direta. Na primeira passagem, são


executadas n-1 comparações; na segunda, são n-2 comparações, e assim
sucessivamente. Nestas condições, obtém-se o seguinte número de comparações:

n * (n − 1)
(n − 1)+ (n − 2)+ (n − 3)+ ..... + 3 + 2 + 1 = .
2

Exercício: Obtenha a fórmula final apresentada acima.

Isto significa que a ordenação por seleção direta é O(n2). Esta é a mesma ordem do
algoritmo apresentado para o método da bolha, contudo, o tempo de execução do
método de seleção direta é menor.

página 12
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

III.4. ORDENAÇÃO POR INSERÇÃO

III.4.1. Inserção simples

O processo de inserção simples consiste em dividir o vetor a ser ordenado em dois


segmentos, o primeiro contendo os elementos já ordenados e o segundo os não
ordenados.

Algoritmo
O algoritmo pode ser resumido da seguinte maneira:

a) O primeiro elemento está no vetor ordenado e os demais no vetor


desordenado;
b) Retira-se o primeiro elemento do vetor desordenado, colocando-o no vetor
ordenado. Nesse processo, são realizadas as comparações necessárias para
inserí-lo na sua posição correta;
c) Repete-se o processo até que todos os elementos do vetor desordenado
tenham passado para o vetor ordenado.

Um exemplo do algoritmo na notação de pseudocódigo é apresentado a seguir.

Pseudocódigo

Função Inserção_simples (V[ ] : Vetor de inteiro, maximo: inteiro)


Inicio
i, j, k, trab: inteiro

para j ← 2 até maximo faça


trab ← vetor[j]
i← j-1
enquanto (i > 0) e (vetor[i] > trab) faça
vetor[i+1] ← vetor[i]
i← i-1
fim enquanto
vetor[i+1] ← trab
fim para
fim

Exercício: Implemente o algoritmo apresentado acima na


linguagem C.

Observe que neste algoritmo o próprio vetor é utilizado no processo de ordenação,


não consumindo, portanto, memória para a separação dos segmentos de vetor.
Consome-se um pouco de memória somente para o armazenamento de variáveis de
trabalho (auxiliares).

página 13
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Exemplo

25 57 48 37 12 92 86 33
1o passo 25 57 48 37 12 92 86 33 // separa o primeiro valor – A região
cinza corresponde ao vetor não
ordenado. O número em negrito
será incluído no primeiro segmento
já na posição correta.
2o. passo 25 57 48 37 12 92 86 33
3o. passo 25 48 57 37 12 92 86 33
4o. passo 25 37 48 57 12 92 86 33
5o. passo 12 25 37 48 57 92 86 33
5o. passo 12 25 37 48 57 92 86 33
6o. passo 12 25 37 48 57 86 92 33
7o. passo 12 25 33 37 48 57 86 92 //fim do processo

Eficiência da Ordenação pelo Método de Inserção Simples

Se o vetor inicial estiver ordenado, somente uma comparação será realizada em


cada passagem (laço j), e a ordenação comporta-se como O(n). Se o vetor inicial
estiver ordenado na ordem inversa (pior caso), o número total de comparações será
dado por :

n * (n − 1)
(n − 1)+ (n − 2)+ (n − 3)+ ..... + 3 + 2 + 1 = ,
2

ou seja, é O(n2).

Este método é, em geral, melhor que o método da bolha. Quanto mais ordenado
estiver o vetor inicial, mais eficiente será a ordenação por inserção simples.

Observe que neste algoritmo o próprio vetor é utilizado no processo de ordenação,


não consumindo, portanto, memória para a separação dos segmentos de vetor.
Consome-se um pouco de memória somente para o armazenamento de variáveis de
trabalho (auxiliares).

Há meios de otimizar a ordenação por inserção simples, mas a ordem do algoritmo


continua sendo O(n2).

página 14
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

III.4.2. Ordenação de Shell (shellsort)

Trata-se de uma extensão do processo de inserção simples. No método de


ordenação por inserção simples são trocados somente elementos adjacentes. Como
vimos, este procedimento leva a desempenhos de O(n2), no pior caso. A idéia básica
do shellsort é subdividir o vetor em blocos de tamanho h e rearranjar (ordenar) os
dados comparando elementos afastados (de h posições). Assim, o valor A[1] é
comparado com A[h+1], A[2] com A[h+2], e assim por diante. Se h é grande, pode-
se mover elementos que estão bastante afastados no vetor. O valor de h é diminuído
a cada ciclo de ordenação, até atingir o valor 1 (neste caso, a ordenação se reduz a
uma inserção simples).
O ideal é que a os valores de h sejam números primos entre si, de forma a garantir
sobreposição de regiões de subdivisão.

O algoritmo na notação pseudocódigo é apresentado a seguir.

Pseudocódigo

Função shellsort (V[ ] : Vetor de inteiro, maximo: inteiro, h[ ] : vetor de inteiro, m : inteiro)
inicio
i, j, k, trab: inteiro

para k ← m até 1 decr 1 faça

para j ← h[k] +1 até maximo faça


trab ← vetor[j]
i ← j – h[k]
enquanto (i > 0) e (vetor[i] > trab) faça
vetor[i+h[k]] ← vetor[i]
i ← i – h[k]
fim enquanto
vetor[i+h[k]] ← trab
fim para

fim para
fim

Exercício: Implemente o algoritmo apresentado acima na


linguagem C.

Compare este pseudocódigo com o apresentado para o processo de ordenação por


inserção simples. Valem aqui os mesmos comentários feitos para o caso de inserção
simples.

Observe que a construção da seqüência de tamanho da subdivisão do vetor é


deixada para definição externa.

página 15
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Acompanhem com atenção os exemplos a seguir.

Exemplo 1: ordenação com seqüência h={1,3,4}.


(Observem que estes números são primos entre si).

25 57 48 37 12 92 86 33
o
1 passo 25 57 48 37 12 92 86 33 h = 4
foram comparadas as posições 1 com 5
(trocados 25 e 12), 2 com 6 (sem
trocas), 3 com 7 (sem trocas) e 4 com 8
(trocados 37 com 33).

2o. passo 12 57 48 33 25 92 86 37 h = 3
foram comparadas as posições 1 com 4,
com 7 (sem trocas), 2 com 5 com 8 (2
trocas) e 3 com 6 (sem trocas)

3o. passo 12 25 48 33 37 92 86 57 h = 1
A partir deste ponto o procedimento se
reduz ao da ordenação por inserção
simples
4o. passo 12 25 33 37 48 57 86 92 resultado final.

Exemplo 2: ordenação com seqüência h={1,2,3}.


(Observem que estes números também são primos entre si).

25 57 48 37 12 92 86 33
o
1 passo 25 57 48 37 12 92 86 33 h = 3
foram comparadas as posições 1 com 4,
com 7 (sem trocas), 2 com 5 com 8 (2
trocas) e 3 com 6 (sem trocas)

2o. passo 25 12 48 37 33 92 86 57 h = 2
posições comparadas : 1,3,5,7 (1 troca)
posições comparadas : 2,4,6,8 (1troca)

3o. passo 25 12 33 37 48 57 86 92 h = 1
A partir deste ponto o procedimento se
reduz ao da ordenação por inserção
simples
4o. passo 12 25 33 37 48 57 86 92 resultado final.

página 16
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Exemplo 3: ordenação com seqüência h={1,3}.

25 57 48 37 12 92 86 33
o
1 passo 25 57 48 37 12 92 86 33 h = 3
foram comparadas as posições 1 com 4,
com 7 (sem trocas), 2 com 5 com 8 (2
trocas) e 3 com 6 (sem trocas)

2o. passo 25 12 48 37 33 92 86 57 h = 1

3o. passo 12 25 33 37 48 57 86 92 resultado final.

Exercício: Acompanhe passo a passo o algoritmo de ordenação


por inserção simples para h = 1 nos três exemplos anteriores .

Eficiência da Ordenação pelo Método shellsort

A análise de eficiência da ordenação de Shell é complicada, do ponto de vista


matemático. Isto porque as exigências de tempo para uma classificação específica
dependem do número de elementos do vetor h e de seus valores. Por exemplo:

• Foi possível estabelecer que o shellsort nunca executa mais do que N1,5
comparações para incrementos na seqüência (inversa) {1,4,13,40,121, ...}.
• Existem algumas seqüências de incrementos que provavelmente resultam em
desempenhos ruins (só para citar uma : { 1,2,4,8,16,32,64,....}. Nestas
condições elementos em posições impares não são comparados com
elementos em posições pares até que h seja 1.

A forma funcional do tempo de execução do algoritmo shellsort não é conhecida. O


que é conhecido é que o tempo de execução não é muito sensível à ordenação
inicial do vetor .

O shellsort é muito utilizado para ordenação de “vetores”de tamanhos


intermediários.

Finalmente, a mesma estratégia pode ser utilizada para melhorar o desempenho da


ordenação pelo método da bolha

página 17
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

III.5. ORDENAÇÃO EM ÁRVORE

III.5.1. Ordenação por heapsort


Algoritmo básico
1. Constrói-se uma árvore binária com todos os elementos do vetor;

2. Transforma-se a árvore em um heap:


a. A transformação é realizada do nível mais baixo até a raiz: coloca-se
em cada nó um valor maior do que em seus sucessores imediatos.
b. Repete-se o processo até que em cada nó o valor seja maior do que
em seus sucessores imediatos;

3. Realiza-se a classificação do heap:


a. Troca-se a posição do maior valor contido na árvore (valor que está na
raiz) com a posição de maior índice na árvore.
b. A posição de maior índice é retirada da árvore;
c. Verifica-se se a propriedade do heap foi mantida após a troca. Se não,
restaura-se o heap.
d. O processo é repetido até que o heap tenha apenas um elemento.

Pseudocódigo

Vetores c e e contêm chaves e endereços,


n corresponde ao número de elementos nos vetores c e e.

função heapsort (c, e : vetor[1 .. n] de inteiro; n : inteiro)

variáveis:
i,k,n1,ch,ed: inteiro

Inicio

rem criação do heap


i ← n div 2
para k de i até 1 faça
inicio
execute insereheap(c,e, n, k, n)
fim para

rem ordenação
para n1 de n-1 até 1 faça
inicio
ch ← c[1]; c[1] ← c[n1 +1]; c[n1+1] ← ch;
ed ← e[1]; e[1] ← e[n1 +1]; e[n1+1] ← ed;
execute insereheap (c, e, n, 1, n1)
fim para

fim heapsort

página 18
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

k : posição onde será feita a inserção


n1 : limite do heap no vetor

função insereheap(c,e : vetor[1..n] de inteiro; n,k,n1:inteiro)


variáveis
i : inteiro;
troca : lógica;

inicio
i ← k; troca ← true
enquanto troca faça
se valor(c, n1,2*i) > valor (c, n1, 2*i + 1) então
h ← 2*i
senão h ← 2*i + 1

se c[i] < valor (c, n1, h) então


inicio
ch ← c[i]; c[i] ← c[h]; c[h] ← ch;
ed ← e[i]; e[i] ← e[h]; e[h] ← ed;
i ← h
fim
senão troca ← false

fim enquanto
fim insereheap

rem minint corresponde ao menor inteiro possivel

função valor : inteiro ( c: vetor [ 1 ..n] de inteiro; n, i : inteiro)


inicio
se i > n então retorne minint;
senão retorne c[i]
fim valor

Lembrete: Seja um Heap representado por uma árvore binária. A árvore é


formada por nodos e de cada nodo apresenta um nodo pai (parent) e
até dois nodos filhos (children). A árvore apresenta um nodo
denominado raiz (root) a partir do qual são criados os f ilhos,
seguindo a regra anterior. A condição para que uma árvore seja um
heap é que a chave em cada nodo seja maior do que (ou igual a) as
chaves presentes nos nodos filhos.

Exemplo:
posição no vetor 1 2 3 4 5 6 7 8
valor 25 57 48 37 12 92 86 33

página 19
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Transformação da árvore em heap

25 1 25 1
2 3 2 3
57 48 57 92
4 5 6 7 4 5 6 7
37 12 92 86 37 12 48 86

33 8 33 8

valor 25 57 48 37 12 92 86 33 valor 25 57 92 37 12 48 86 33

92 1 92 1
2 3 2 3
57 25 57 86
4 5 6 7 4 5 6 7
37 12 48 86 37 12 48 25

33 8 33 8

Classificação

92 1 33 1
2 3 2 3
57 86 57 86
4 5 6 7 4 5 6 7
37 12 48 25 37 12 48 25

33 8 92 8

Troca-se o valor da raiz com o valor da posição


valor 92 57 86 37 12 48 25 33 de maior índice e retira-se a posição de maior
índice do heap.

86 1 86 1
2 3 2 3
57 33 57 48
4 5 6 7 4 5 6 7
37 12 48 25 37 12 33 25

92 8 92 8

Restaura-se a propriedade do heap.


valor 86 57 48 37 12 33 25 92

página 20
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

25 1 57 1
2 3 2 3
57 48 25 48
4 5 6 7 4 5 6 7
37 12 33 86 37 12 33 86

92 8 92 8

Troca-se o valor da raiz com o valor da posição Restaura-se a propriedade do heap


de maior índice e retira-se a posição de maior
índice do heap

57 1 33 1
2 3 2 3
37 48 37 48
4 5 6 7 4 5 6 7
25 12 33 86 25 12 57 86

92 8 92 8

Troca-se o valor da raiz com o valor da posição


valor 57 37 48 25 12 33 86 92
de maior índice e retira-se a posição de maior
índice do heap

48 1 12 1
2 3 2 3
37 33 37 33
4 5 6 7 4 5 6 7
25 12 57 86 25 48 57 86

92 8 92 8

Restaura-se a propriedade do heap Troca-se o valor da raiz com o valor da posição


de maior índice e retira-se a posição de maior
valor 48 37 33 25 12 57 86 92 índice do heap

37 1 37 1
2 3 2 3
12 33 25 33
4 5 6 7 4 5 6 7
25 48 57 86 12 48 57 86

92 8 92 8

Restaura-se a propriedade do heap


valor 37 25 33 12 48 57 86 92

página 21
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

12 1 33 1
2 3 2 3
25 33 25 12
4 5 6 7 4 5 6 7
37 48 57 86 37 48 57 86

92 8 92 8

Troca-se o valor da raiz com o valor da posição Restaura-se a propriedade do heap


de maior índice e retira-se a posição de maior
índice do heap valor 33 25 12 37 48 57 86 92

12 1 25 1
2 3 2 3
25 33 12 33
4 5 6 7 4 5 6 7
37 48 57 86 37 48 57 86

92 8 92 8

Troca-se o valor da raiz com o valor da posição Restaura-se a propriedade do heap


de maior índice e retira-se a posição de maior
índice do heap valor 25 12 33 37 48 57 86 92

12 1
2 3
Ao final do processo, o vetor estará
ordenado:
25 33
4 5 6 7
37 48 57 86 posição 1 2 3 4 5 6 7 8

valor 12 25 33 37 48 57 86 92
92 8

Fim do processo

Exercício: Implementar o heap como um vetor é muito fácil. Qual a regra


para acessar os dois filhos de um elemento V[i]? E qual a
regra para se ter acesso ao pai de um elemento (nodo) V[j]?

Desempenho

Este método não utiliza memória adicional para realizar a ordenação de um vetor.
Além disso, o Heapsort ordena N elementos em N log N passos, independente da
entrada de dados. Portanto, o heapsort é O(N log (N)).

página 22
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Exercício: Faça uma avaliação do número médio de comparações


necessárias para ordenar um vetor com o heapsort.

Exercício: Que outras operações (ou passos) são importantes no


heapsort? Faça uma avaliação do número médio de
cada uma dessas operações.

Exercício: A partir dos dados obtidos nos exercícios anteriores,


deduza a ordem do algoritmo.

III.6. UMA COMPARAÇÃO SUPERFICIAL DOS ALGORITMOS DE ORDENAÇÃO

A seguir são apresentadas tabelas com o tempo de execução da ordenação de


alguns dos algoritmos apresentados neste capítulo. São consideradas três situações
diferentes de entrada de dados. Os dados apresentados foram retirados da
referência [3].

Tabela 1: Dados de entrada em ordem aleatória.

N 500 5000 10000 30000


Inserção 11,3 87 161 0
Shell 1,2 1,6 1,7 2
Quick 1 1 1 1
Seleção 16,2 124 228 0
Heap 1,5 1,6 1,6 1,6

Tabela 2: Dados de entrada em ordem crescente.

N 500 5000 10000 30000


Inserção 1 1 1 1
Shell 3,9 6,8 7,3 8,1
Quick 4,1 6,3 6,8 7,1
Seleção 128 1524 3066 0
Heap 12,2 20,8 22,4 24,6

Tabela 3: Dados de entrada em ordem decrescente.

N 500 5000 10000 30000


Inserção 40,3 305 575 0
Shell 1,5 1,5 1,6 1,6
Quick 1 1 1 1
Seleção 29,3 221 417 0
Heap 2,5 2,7 2,7 2,9

página 23
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

Os dados das tabelas foram normalizados para o algoritmo que apresenta o melhor
desempenho no teste. Observem também que o desempenho relativo dos vários
algoritmos varia muito, dependendo da organização dos dados de entrada.

Exercício: Implemente cada um dos algoritmos apresentados neste


capítulo, na linguagem de sua preferência, e compare o tempo
necessário para realizar a ordenação de um vetor dado.
Verifique se o tamanho do vetor de dados influencia os
resultados. Apresente esses resultados em uma ou mais tabelas.

Atenção: Para realizar esta avaliação é importante que sejam utilizados,


também, vetores de teste com um número muito grande de
elementos. Para gerar esses vetores, crie uma função que gera
os elementos aleatória ou ordenadamente.

III.7. COMENTÁRIOS ADICIONAIS

Todos os exemplos que apresentamos neste capítulo envolvem a ordenação de


seqüências de números inteiros, organizados em vetores. Em todos os casos,
consideramos, implicitamente, que todo o conjunto de dados a ser ordenado está
contido na memória primária do computador.

Na prática, ocorre a necessidade de ordenar um número realmente grande de


dados, dados esses mais complexos do que um número inteiro simples. Se a
quantidade de dados envolvida é muito grande, pode ocorrer que a memória
primária não seja suficiente para acolher toda a massa de dados. Nestes casos, é
necessário trabalhar, direta ou indiretamente, com dispositivos de armazenamento
de dados secundários (discos rígidos ou CDs, por exemplo). Se os dados são mais
complexos do que um simples número inteiro (o que, em geral, ocorre) e eles devem
ser ordenados de acordo com um determinado critério, o número de operações de
troca de posição na memória, por exemplo, pode ser muito maior. Esses dados são
denominados registros.

Contudo, os conceitos discutidos até o momento, no que diz respeito à análise dos
algoritmos, continuam válidos. O que muda é o fator multiplicativo (não explicitado
na notação de ordem – consulte novamente a definição de ordem Omicron
apresentada na apostila de análise de algoritmos), o que determina o tempo total de
execução, mas não o comportamento genérico dos vários algoritmos.

página 24
Projeto e Análise de Algoritmos
Algoritmos de Ordenação

III.8. BIBLIOGRAFIA

[1] Robert Sedgewick, Algorithms in C, Addison Wesley Publishing Co., 1990

[2] Robert Sedgewick, Algorithms in C++, Parts 1 -4, Terceira Edição, Addison
Wesley Publishing Co., 1998

[3] Celso Roberto Moraes, Estruturas de dados e algoritmos, uma abordagem


didática, São Paulo,Ed. Berkeley, 2001

[4] A. M. Tenenbaum, Y. Langsam, M. J., Augenstein, Estruturas de dados usando


C, São Paulo, Makron Books, 1995

[5] P. Veloso, C. dos Santos, P. Azeredi, A. Furtado, Estruturas de dados, 15ª ed.
Ed. Campus, 1983

[6] S. L. Pereira, Estruturas de Dados Fundamentais, Conceitos e Aplicações, 3ª ed.


São Paulo, Ed. Érica, 1996

[7] R. Lafore, Aprenda em 24 horas estrutura de dados e algoritmos. Rio de Janeiro.


Editora Campus Ltda. 1999.

página 25

Você também pode gostar