19
UNIVERSIDADE FEDERAL DO ABC ANDRÉ RICARDO FREDERICO ORLANDO DA SILVA JUNIOR ANÁLISE EMPÍRICA DE ALGORITMOS DE ORDENAÇÃO Santo André Maio de 2012

Análise empírica de algoritmos de ordenação

Embed Size (px)

DESCRIPTION

Trabalho apresentado à Universidade Federal do ABC como parte para aprovação no curso de Análise de Algoritmos e Estrutura de Dados.O objetivo principal deste trabalho é estudar empiricamente a complexidade de tempo dos algoritmos de ordenação interna.

Citation preview

Page 1: Análise empírica de algoritmos de ordenação

UNIVERSIDADE FEDERAL DO ABC

ANDRÉ RICARDO FREDERICO

ORLANDO DA SILVA JUNIOR

ANÁLISE EMPÍRICA DE ALGORITMOS DE ORDENAÇÃO

Santo André

Maio de 2012

Page 2: Análise empírica de algoritmos de ordenação

ANDRÉ RICARDO FREDERICO

ORLANDO DA SILVA JUNIOR

ANÁLISE EMPÍRICA DE ALGORITMOS DE ORDENAÇÃO

Trabalho apresentado à Universidade

Federal do ABC como parte para

aprovação no curso de Análise de

Algoritmos e Estrutura de Dados,

ministrado pelo Prof. Dr. André Balan e

Prof. Dr. Daniel Martin.

Santo André

Maio de 2012

Page 3: Análise empírica de algoritmos de ordenação

2

SUMÁRIO

1 INTRODUÇÃO ..................................................................................................................... 3

1.1 Objetivos ............................................................................................................................... 3

2 METODOLOGIA .................................................................................................................. 4

2.1 Experimentos ........................................................................................................................ 4

3 RESULTADOS ...................................................................................................................... 6

3.1 Bubble Sort ........................................................................................................................... 6

3.2 Selection Sort ........................................................................................................................ 7

3.3 Insertion Sort ........................................................................................................................ 8

3.4 Quick Sort ............................................................................................................................. 9

3.5 Heap Sort ............................................................................................................................ 10

3.6 Merge Sort .......................................................................................................................... 12

3.7 Shell Sort ............................................................................................................................ 12

3.8 Shell Sort – Knuth .............................................................................................................. 13

3.9 Shell Sort – Pardons ........................................................................................................... 14

3.10 Ordenação Inversa ............................................................................................................ 14

ANÁLISE DOS RESULTADOS E CONCLUSÃO ............................................................. 16

REFERÊNCIAS BIBLIOGRÁFICAS ................................................................................. 18

Page 4: Análise empírica de algoritmos de ordenação

3

1 INTRODUÇÃO

Um algoritmo consiste em um procedimento com um conjunto regras não ambíguas

que especificam, para cada entrada, uma sequência finita de operações, resultando em uma

saída correspondente (TOSCANI; VELOSO, 2002). Assim, analisar um algoritmo significa

prever os recursos que o algoritmo necessitará (CORMEN et al., 2002).

A previsão de recursos necessários, neste trabalho, é obtida através da análise empírica

do tempo de execução de cada algoritmo. Com esta metodologia, espera-se obter o tempo

médio de um algoritmo para diferentes tamanhos de entrada. Esse tipo de avaliação permite

comparar a praticidade com que os algoritmos podem ser utilizados. No entanto, para que o

modelo matemático que avalia a complexidade de algoritmos não se torne inútil, também é

necessária a sua presença nessa avaliação.

É indiscutível a importância dos algoritmos de ordenação na ciência da computação

(CORMEN et. al, 2002; MCCONNELL, 2006). Neste trabalho, os principais algoritmos de

ordenação são avaliados e comparados.

Basicamente, um algoritmo de ordenação é aquele que resolve um problema de

ordenação. Formalmente, um problema de ordenação pode ser definido como uma sequência

de números ⟨ ⟩ cuja saída é uma permutação da sequência de entrada, tal que

(CORMEN et al., 2002).

1.1 Objetivos

O objetivo principal deste trabalho é estudar empiricamente a complexidade de tempo

dos algoritmos de ordenação interna.

Para alcançar esse objetivo, outros objetivos específicos se tornam necessários. Para

este trabalho, os objetivos específicos são:

a) Estudar as características gerais e a complexidade de cada algoritmo utilizado;

b) Implementar em uma linguagem adequada todos os algoritmos utilizados, a fim de

que fatores externos de desempenho não prejudiquem a avaliação final e que a

leitura do código seja facilmente compreensível;

c) Analisar e comparar o tempo médio do algoritmo com sua complexidade temporal.

d) Realizar, analisar e comparar o desempenho entre os algoritmos avaliados.

Page 5: Análise empírica de algoritmos de ordenação

4

2 METODOLOGIA

A metodologia utilizada neste trabalho seguiu as diretrizes propostas pela atividade.

Assim, foram utilizados sete algoritmos de ordenação sobre seis conjuntos de dados aleatórios

diferentes conforme a variação de suas sementes mais um conjunto extra inversamente

ordenado.

Os conjuntos de dados possuíam nove diferentes tamanhos. Cada um desses conjuntos,

escolhidos pela diretriz da atividade proposta, comportava, respectivamente, 10 mil, 30 mil,

90 mil, 270 mil, 810 mil, 2430 mil, 7290 mil, 21870 mil e 65610 mil elementos. No caso

deste trabalho, esses conjuntos agregaram apenas números inteiros, embora pudessem ser

utilizados outros tipos de dados.

As sequências utilizadas para a geração dos números aleatórios tiveram as sementes: 4,

81, 151, 1601, 2307 e 4207. Por fim, os algoritmos de ordenação utilizados foram divididos

em:

a) Ineficientes: Bubble sort, Selection sort e Insertion sort; e

b) Eficientes: Quick sort, Heap sort, Merge sort e Shell sort (com 3 variações: padrão,

Knuth e Pardons).

2.1 Experimentos

Ao todo, o projeto contabilizou nove métodos de ordenação, nove tamanhos diferentes

de conjunto de dados e seis sequências aleatórias, totalizando 486 ordenações. Na rodada

inversa, os nove algoritmos foram utilizados para prever o pior caso: ordenar um conjunto

inversamente ordenado.

Foram utilizados dois computadores para realizar este experimento. O primeiro

computador é um notebook com processador Intel Core 2 Duo 2.10 Ghz 32-bits, 4 GB de

memória RAM. O segundo computador é um notebook com processador Intel Core 2 Duo 2.0

Ghz 32-bits, 3 GB de memória. Enquanto o primeiro computador utilizou-se do sistema

operacional Windows 7, o segundo utilizou o Linux Ubutu 11.10.

Para a coleta dos dados e posterior análise, os resultados de ambos os computadores

foram aproveitados, sem, no entanto, intercalar as respostas dos algoritmos ou suas sequências

numéricas. Isto foi realizado para: (a) analisar a influência do computador sobre a execução

dos algoritmos em cada conjunto de dados e (b) acelerar os experimentos, que poderiam

demorar horas ou dias.

Page 6: Análise empírica de algoritmos de ordenação

5

As funções de tempo próprias de cada sistema operacional foram implementadas e

utilizadas em seus respectivos ambientes.

Page 7: Análise empírica de algoritmos de ordenação

6

3 RESULTADOS

Com os experimentos, notou-se que a partir do tamanho de entrada 2430 mil os

algoritmos ineficientes estavam levando mais de duas horas para serem concluídos. Por esta

razão, este trabalho optou por não continuar executando os algoritmos ineficientes para os

tamanhos maiores que 810 mil elementos e nem os apresentará nestes resultados.

Ainda, para evitar o pior caso do algoritmo Quick Sort, ele foi implementado

parcialmente em modo iterativo e a seleção do pivô se deu de maneira aleatória. Também,

para melhorar a execução do algoritmo Bubble Sort, sua implementação foi modificada de

modo a não executar mais de uma vez o que já foi executado.

Os resultados expressos nos gráficos abaixo apresentam a relação tamanho x tempo de

cada um dos algoritmos utilizados pelo projeto. Os resultados são apresentados por algoritmo

e semente utilizada. Por fim, é apresentado o resultado da rodada inversa.

3.1 Bubble Sort

O Bubble Sort é um algoritmo de ordenação interna que compara pares de elementos,

trocando aqueles que estão fora de ordem até que a lista esteja ordenada (MCCONNELL,

2006).

A Figura 1 apresenta a relação tamanho do conjunto x tempo médio, em

milissegundos, do algoritmo Bubble Sort para as seis sementes utilizadas. Os tamanhos

presentes no gráfico são 10 mil, 30 mil e 90 mil elementos. A Figura 2 apresenta a mesma

relação da Figura 1, mas apenas para os tamanhos 270 mil e 810 mil elementos.

Page 8: Análise empírica de algoritmos de ordenação

7

Figura 1 – Gráfico comparativo do tempo médio do algoritmo

Figura 2 – Gráfico comparativo do tempo médio do algoritmo

3.2 Selection Sort

O Selection Sort é um dos algoritmos de ordenação mais simples que existe.

Basicamente, o algoritmo divide a lista em duas listas: ordenada e desordenada. Percorrendo a

lista desordenada, o algoritmo seleciona nela o menor valor e a insere na lista ordenada

(BALAN, 2012; SEDGWICK, 1990).

Assim como o Bubble Sort, o algoritmo Selection Sort está dividido em duas análises:

do tamanho 10 mil até o tamanho 90 mil (Figura 3) e do tamanho 270 mil até o tamanho 810

mil (Figura 4).

0

10000

20000

30000

40000

50000

60000

10000 30000 90000

Te

mp

o m

éd

io (

ms)

Bubble Sort

0

1000000

2000000

3000000

4000000

5000000

6000000

270000 810000

Te

mp

o m

éd

io (

ms)

Bubble Sort

Page 9: Análise empírica de algoritmos de ordenação

8

Figura 3 – Gráfico comparativo do tempo médio do algoritmo

Figura 4 – Gráfico comparativo do tempo médio do algoritmo

3.3 Insertion Sort

A ideia por trás do Insertion Sort é ordenar uma lista através da inserção de elementos.

Se um elemento é inserido na lista, ele já deve ser colocado em sua posição correta

(MCCONNELL, 2006).

Assim como o Selection Sort, o algoritmo Insertion Sort também subdivide suas

análises no mesmo espaço de tamanho de conjuntos. A Figura 5 e a Figura 6 apresentam essas

análises.

0

10000

20000

30000

40000

50000

60000

70000

10000 30000 90000

Te

mp

o m

éd

io (

ms)

Selection Sort

0

1000000

2000000

3000000

4000000

5000000

6000000

270000 810000

Te

mp

o m

éd

io (

ms)

Selection Sort

Page 10: Análise empírica de algoritmos de ordenação

9

Figura 5 – Gráfico comparativo do tempo médio do algoritmo

Figura 6 – Gráfico comparativo do tempo médio do algoritmo

3.4 Quick Sort

O Quick Sort é um dos melhor algoritmos de ordenação que existe. Recursivamente, o

algoritmo escolhe um elemento e divide a lista em duas partes: a primeira, com todos os

elementos menores que o elemento escolhido; e a segunda, com todos os maiores. Quando a

lista atinge o tamanho mínimo, o algoritmo, então, ordena e devolve o pequeno conjunto

ordenado (MCCONNELL, 2006; SEDGWICK, 1990).

O Quick Sort foi o primeiro algoritmo da categoria dos algoritmos eficientes utilizado.

Para apresentar seus resultados e dos demais algoritmos eficientes, duas análises foram

realizadas: a primeira abrange os seis primeiros tamanhos de conjuntos de dados (de 10 mil

0

2000

4000

6000

8000

10000

12000

14000

16000

10000 30000 90000

Te

mp

o m

éd

io (

ms)

Insertion Sort

0

200000

400000

600000

800000

1000000

1200000

1400000

1600000

270000 810000

Te

mp

o m

éd

io (

ms)

Insertion Sort

Page 11: Análise empírica de algoritmos de ordenação

10

elementos a 2430 mil elementos) e a segunda abrange os três últimos conjuntos (de 7290 mil

elementos a 65610 mil elementos).

A primeira análise é apresentada na Figura 7, enquanto que a segunda análise é

apresentada na Figura 8.

Figura 7 – Gráfico comparativo do tempo médio do algoritmo

Figura 8 – Gráfico comparativo do tempo médio do algoritmo

3.5 Heap Sort

O Heap Sort é um algoritmo baseado na árvore binária Heap (máxima), onde para

cada subárvore o valor da raiz é maior que dos filhos. A ideia geral do Heap Sort é a

construção do Heap: o maior elemento será sempre a raiz da árvore; a raiz é copiada para a

0

100

200

300

400

500

600

700

800

900

10000 30000 90000 270000 810000 2430000

Te

mp

o m

éd

io (

ms)

Quick Sort

0

5000

10000

15000

20000

25000

7290000 21870000 65610000

Te

mp

o m

éd

io (

ms)

Quick Sort

Page 12: Análise empírica de algoritmos de ordenação

11

última posição e, então, o Heap é reconstruído, até que a lista esteja ordenada

(MCCONNELL, 2006).

Para apresentar os resultados do Heap Sort, duas análises foram realizadas: a primeira

abrange os seis primeiros tamanhos de conjuntos de dados (de 10 mil elementos a 810 mil

elementos) e a segunda abrange os três últimos conjuntos (de 2430 mil elementos a 65610 mil

elementos).

Figura 9 – Gráfico comparativo do tempo médio do algoritmo

Figura 10 – Gráfico comparativo do tempo médio do algoritmo

0

100

200

300

400

500

600

700

800

10000 30000 90000 270000 810000

Te

mp

o m

éd

io (

ms)

Heap Sort

0

20000

40000

60000

80000

100000

120000

2430000 7290000 21870000 65610000

Te

mp

o m

éd

io (

ms)

Heap Sort

Page 13: Análise empírica de algoritmos de ordenação

12

3.6 Merge Sort

O Merge Sort é baseado na ideia de que unir duas listas ordenadas é um processo

rápido. Sendo que uma lista com apenas um elemento já está ordenada, o Merge Sort quebra

as listas até que elas tenham esse tamanho único e depois as une, recursivamente.

Para o algoritmo Merge Sort, foi realizada apenas uma análise. Conforme se percebe

na Figura 11, os diferentes tamanhos não desbalancearam totalmente o gráfico, já que a faixa

de tempo não possui uma largura tão ampla de valores, como nos demais algoritmos

analisados.

Figura 11 – Gráfico comparativo do tempo médio do algoritmo

3.7 Shell Sort

O algoritmo Shell Sort é uma variação do algoritmo de inserção. A ideia por trás do

Shell Sort é inserir os elementos em suas posições corretas através de passos mais largos. O

Shell Sort utiliza uma sequência de incrementos que determina qual é o próximo elemento a

ser ordenado na subsequência (BALAN, 2012).

Para o algoritmo Shell Sort, quatro análises foram realizadas. Nas duas primeiras

análises, é verificado a faixas entre (a) 10 mil elementos e 810 mil elementos e (b) 2430 mil

elementos e 65610 mil elementos. Nas duas últimas análises, todas as faixas de valores são

comparadas, porém apenas nas versões de Knuth e Pardons, nos subcapítulos seguintes.

0

5000

10000

15000

20000

25000

30000

35000

40000

Te

mp

o m

éd

io (

ms)

Merge Sort

Page 14: Análise empírica de algoritmos de ordenação

13

Essa divisão foi feita para que seja possível analisar o algoritmo como um todo,

independente de sua versão. Como é possível notar, os gráficos das versões de Knuth e

Pardons aproximam-se um do outro e da versão original do algoritmo Shell Sort.

A Figura 12 e a Figura 13 apresentam a análise gráfica do algoritmo Shell Sort em sua

versão original.

Figura 12 – Gráfico comparativo do tempo médio do algoritmo

Figura 13 – Gráfico comparativo do tempo médio do algoritmo

3.8 Shell Sort – Knuth

A Figura 14 apresenta a análise do algoritmo Shell Sort – versão Knuth.

0

100

200

300

400

500

600

700

800

900

10000 30000 90000 270000 810000

Te

mp

o m

éd

io (

ms)

Shell Sort

0

10000

20000

30000

40000

50000

60000

70000

80000

90000

100000

2430000 7290000 21870000 65610000

Te

mp

o m

éd

io (

ms)

Shell Sort

Page 15: Análise empírica de algoritmos de ordenação

14

Figura 14 – Gráfico comparativo do tempo médio do algoritmo

3.9 Shell Sort – Pardons

A Figura 15 apresenta a análise do algoritmo Shell Sort – versão Pardons.

Figura 15 – Gráfico comparativo do tempo médio do algoritmo

3.10 Ordenação Inversa

Por fim, é apresentada nesta seção a rodada da ordenação inversa. Nesta atividade, os

algoritmos ordenaram um conjunto de dados com 50 mil elementos. Nesse conjunto, os

elementos foram inseridos em ordem decrescente sobre uma com distribuição linear.

0

10000

20000

30000

40000

50000

60000

70000

80000

90000

100000T

em

po

dio

(m

s)

Shell Sort - Knuth

0

5000

10000

15000

20000

25000

30000

35000

40000

45000

50000

Te

mp

o m

éd

io (

ms)

Shell Sort - Pardons

Page 16: Análise empírica de algoritmos de ordenação

15

A finalidade dessa rodada é avaliar os algoritmos na certeza de seus piores casos. A

Figura 16 apresenta a análise realizada nos algoritmos ineficientes e a Figura 17, nos

algoritmos eficientes.

Figura 16 – Gráfico comparativo da rodada inversa nos algoritmos ineficientes

Figura 16 – Gráfico comparativo da rodada inversa nos algoritmos eficientes

0

2000

4000

6000

8000

10000

12000

14000

16000

18000

20000

Bubble Sort Selection Sort Insertion Sort

Te

mp

o (

ms)

Ineficientes

14,4

14,6

14,8

15,0

15,2

15,4

15,6

15,8

16,0

16,2

Quick Sort Heap Sort Merge Sort Shell Sort Shell Sort -Knuth

Shell Sort -Pardons

Te

mp

o (

ms)

Eficientes

Page 17: Análise empírica de algoritmos de ordenação

16

4 ANÁLISE DOS RESULTADOS E CONCLUSÃO

Neste capítulo serão analisados os resultados dos experimentos e serão apresentadas as

conclusões gerais do projeto.

Para que a análise empírica possa auxiliar este estudo, é interessante também analisar a

complexidade de tempo de cada um dos algoritmos. A Tabela 1 apresenta a complexidade de

tempo dos algoritmos deste trabalho, segundo a implementação adotada. Para o algoritmo

Shell Sort é apresentada apenas a complexidade de pior caso, já que os demais casos, médio e

melhor, podem variar segundo a sequência de incrementos.

Tabela 1 – Complexidade temporal dos algoritmos implementados

Algoritmo Pior caso Caso médio Melhor caso

Bubble Sort

Selection Sort

Insertion Sort

Quick Sort

Heap Sort

Merge Sort

Shell Sort - -

A análise gráfica de todos os algoritmos mostra que à medida que a quantidade de

elementos a serem ordenados cresce, o desempenho decai e o tempo, em milissegundos,

aumenta. Isto significa que o desempenho dos algoritmos só é aproveitável se o conjunto

possuir uma quantidade máxima N de elementos. Em cada gráfico, é possível verificar o valor

aproximado dessa quantidade.

Com a modificação da implementação, o Bubble Sort mostrou-se mais rápido. Na

maior parte das vezes, bem mais rápido que o Selection Sort. Isto não era esperado, já que

popularmente o Bubble Sort é conhecido por ser o pior algoritmo de ordenação em termos de

desempenho. No geral, entre os algoritmos ineficientes, o Insertion Sort foi o que obteve o

melhor desempenho.

Ao contrário dos algoritmos eficientes, cuja taxa de crescimento foi linearmente baixa,

os algoritmos ineficientes mostraram-se inaptos para grandes quantidades de dados. Para

elementos, a taxa de crescimento dessa classe de algoritmos apresentou baixo

desempenho.

O Quick Sort, primeiro algoritmo eficiente avaliado neste projeto, apresentou

resultados satisfatórios. Embora seu pior caso seja , assim como todos os ineficientes, o

Page 18: Análise empírica de algoritmos de ordenação

17

tempo médio avaliado não ultrapassou o tempo de nenhuma das avaliações dos algoritmos

anteriores. No pior caso esperado deste projeto, ainda ordenou o conjunto com mais de 65

milhões de dados em apenas 20 segundos.

O algoritmo Heap Sort foi o segundo algoritmo eficiente avaliado. Conforme análise

gráfica, este algoritmo alcançou bons resultados em seu desempenho. Embora seja um

algoritmo in-place (que não utiliza memória auxiliar para o processamento) com pior caso

, o Heap Sort não obteve melhores resultados que o Quick Sort.

O algoritmo Merge Sort ainda conseguiu superar o desempenho do Heap Sort. Até

mesmo para os tamanhos maiores, o Merge Sort obteve menor tempo médio entre as

sequências de semente e os tamanhos que o Heap Sort. Junto com o Quick Sort e apenas uma

análise gráfica, a taxa de crescimento do tempo médio do Merge Sort mostrou-se linear em

relação ao tamanho do conjunto.

O algoritmo Shell Sort concluiu a análise de desempenho do projeto. Com três

variações de implementação – tradicional, de Knuth e de Pardons –, o algoritmo Shell Sort foi

um dos melhores algoritmos de ordenação em termos de desempenho. Tanto para pequenas

quantidades quanto para grandes quantidades, a taxa de crescimento desse algoritmo foi

linear.

Para o Shell Sort, é interessante notar que a versão de Pardons obteve um desempenho

significativo em relação a suas demais versões. Embora a versão de Knuth tenha tido um

desempenho melhor que a versão original de Shell, a diferença entre ambas foi pouco

significativa na avaliação dos tamanhos dos conjuntos.

Por fim, a ordenação inversa obteve como melhor resultado entre os ineficientes o

algoritmo Insertion Sort, que rodou em menos da metade do tempo que o Bubble Sort – o

segundo melhor. Entre os algoritmos eficientes, os melhores foram o Quick Sort e a versão

original do algoritmo Shell Sort. Com apenas um milissegundo de diferença, os demais

algoritmos eficientes (Heap Sort, Merge Sort, Shell Sort – Knuth e Shell Sort – Pardons)

ficaram em segundo lugar na avaliação de desempenho geral.

Page 19: Análise empírica de algoritmos de ordenação

18

REFERÊNCIAS BIBLIOGRÁFICAS

BALAN, A. G. R. Notas de Aula. Universidade Federal do ABC (UFABC), 2012.

CORMEN, T. et al. Algoritmos: teoria e prática. Rio de Janeiro: Elsevier, 2002.

MCCONNELL, J. J. Analysis of Algorithms: an active learning approach. USA: Jones and

Bartlett Publishers, 2008.

SEDGEWICK, Robert. Algorithms in C. USA: Addison-Wesley, 1990.

TOSCANI, L. V.; VELOSO, P. A. S. Complexidade de Algoritmos: análise, projeto e

métodos. Porto Alegre: Editora Sagra Luzzatto, 2002.