18
UNIVERSIDADE FEDERAL DO VALE DO SÃO FRANCISCO – UNIVASF COLEGIADO DE ENGENHARIA DA COMPUTAÇÃO – CECOMP RELATÓRIO DE COMPLEXIDADE DE TEMPO E ESPAÇO DE ALGORITMOS Equipe: Rafael Gonçalves, Romullo Abizair, Saulo Rogério. Juazeiro – BA Dezembro de 2013

Estrutura de Dados

Embed Size (px)

DESCRIPTION

Trabalho sobre estrutura de dados e seus metodos.

Citation preview

Page 1: Estrutura de Dados

 

UNIVERSIDADE FEDERAL DO VALE DO SÃO FRANCISCO – UNIVASF

COLEGIADO DE ENGENHARIA DA COMPUTAÇÃO – CECOMP

RELATÓRIO DE COMPLEXIDADE DE TEMPO E ESPAÇO DE ALGORITMOS

Equipe: Rafael Gonçalves,

Romullo Abizair,

Saulo Rogério.

Juazeiro – BA

Dezembro de 2013

Page 2: Estrutura de Dados

  2  

UNIVERSIDADE FEDERAL DO VALE DO SÃO FRANCISCO – UNIVASF

COLEGIADO DE ENGENHARIA DA COMPUTAÇÃO – CECOMP

RAFAEL GONÇALVES, ROMULLO ABIZAIR, SAULO ROGÉRIO.

RELATÓRIO DE COMPLEXIDADE DE TEMPO E ESPAÇO DE ALGORITMOS

Relatório desenvolvido para a

disciplina Estrutura de Dados II,

ministrada pela professora

Ana Emília Melo Queiroz e

usado como critério de avaliação.

Juazeiro – BA

Dezembro de 2013

Page 3: Estrutura de Dados

  3  

Índice

1. Introdução ........................................................................................................................ 4

2. Esquema Básico de um Algoritmo ................................................................................... 5

3. Tamanho da Entrada ........................................................................................................ 6

4. Tempo de Complexidade de um Algoritmo .................................................................... 6

4.1 Análise do Tempo ...................................................................................................... 6

4.2 Análise do Pior, Médio e Melhor casos ...................................................................... 7

4.3 Algoritmos de Ordenação ........................................................................................... 7

4.4 Comportamento das Funções de Tempo ................................................................... 11

4.5 A Análise Matemática e Empírica .............................................................................. 12

4.6 Gráficos Melhor, Médio e Pior casos ......................................................................... 13

4.7 Resultados da Implementação das Análise Matemática e Empírica .......................... 16

4.8 Limite Inferior e Limite Superior ............................................................................... 16

4.9 A eficiência dos Algoritmos na Obtenção dos Resultados ......................................... 16

5. Espaço de Complexidade de um Algoritmo ....................................................................... 17

6. Conclusão ............................................................................................................................ 18

7. Referências Bibliográficas .................................................................................................. 18

Page 4: Estrutura de Dados

  4  

1. Introdução

Assim como fala [ZIVIANI, 1999], os algoritmos fazem parte do nosso dia-dia.

Instruções, receitas, manuais são exemplos de algoritmos.

Algoritmo de modo resumido é um conjunto sequencial e finito de ações que devem ser

executadas para se chegar num objetivo, ou seja, passos necessários para se chegar a uma

resolução de um determinado tipo de problema. Mas, como para cada problema têm-se uma

resolução, encontramos uma incógnita aqui. Podemos ter uma ou várias resoluções para um

mesmo problema por exemplo, e também cada código terá uma complexidade e um tempo

de execução para se chegar ao objetivo, ou seja, cada algoritmo terá sua sequência de passos

e seu tamanho, diferenciando assim de uma outra resolução.

Já de acordo com [LEISERSON,2002] algoritmo nada mais é do que uma receita que mostra

passo a passo os procedimentos necessários para a resolução de uma tarefa. Com isso,

[LEISERSON,2002] aprofunda-se mais um pouco ao dizer que estrutura de dados está

ligada à escolha do melhor algoritmo para a resolução de uma tarefa, daí levamos em conta

questões como o armazenamento e organização dos dados, assim mostramos que estamos

preocupados com o melhor modo para se chegar ao objetivo, o jeito mais rápido e fácil de se

resolver um problema. Existem vários tipos de estruturas de dados e nenhuma delas

funciona perfeitamente para todos os problemas requisitados, com isso, é importante não só

conhecer cada uma delas mais também escolher melhor aquela que irá proporcionar um

desempenho satisfatório.

Como algoritmos estruturados são organizadamente escritos, não tem como

falarmos de estrutura de dados sem mencionar os algoritmos e suas características, nem

como escrever um algoritmo sem pensar em sua estrutura. De acordo com [ZIVIANI, 1999],

programar é basicamente construir um código e estrutura-lo adequadamente, de acordo com

as necessidades dos usuários.

Mesmo que os computadores atuais tenha configurações boas, as máquinas ainda

tem suas limitações, talvez sua memória seja absurdamente grande, mas certas tarefas ainda

levam muito tempo para serem executadas. Se tivéssemos um super computador que fosse

capaz de executar suas ações incrivelmente rápidos, nós não precisaríamos nos preocupar

com a estruturação de algoritmos para solucionar problemas, porque todos os algoritmos

Page 5: Estrutura de Dados

  5  

teriam seus resultados iguais, e utilizaríamos sempre o método mais rápido e fácil de ser

implementado. Por isso devemos dar atenção a importância de criar algoritmos eficientes em

termos de tempo e de espaço alocado na memória para assim termos os melhores resultados

possíveis.

2. Esquema Básico de um Algoritmo

Como já mencionamos anteriormente, os algoritmos são como espécies de

receitas, nas quais têm-se os passos necessários para se realizar uma tarefa. O ideal é que

esse passo a passo seja claro e objetivo, sem ser ambíguo ou redundantes.

Os algoritmos podem ser construídos através de uma linguagem chamada pseudocódigo, que

tem uma formatação e estrutura mais próxima da escrita humana, ajudando assim aos

iniciantes na programação. Evidenciando-se que um algoritmo independe de linguagens de

programação. Em pseudocódigo, o algoritmo posteriormente servirá como uma ponte para

uma linguagem de programação mais desenvolvida e objetiva.

Segundo [VILLAR, 1993], temos algumas regras que são importantes na construção de um

algoritmo. São elas:

• Ser objetivo

• Supor que você está desenvolvendo um algoritmo para pessoas que não trabalham

conhecem informática

• Utilizar frases simples e curtas

• Usar um verbo por frase

• Usar palavras que não tenham um sentido difícil de se entender ou definir

O esquema da figura abaixo ilustra independente de sua complexidade, como os algoritmos

são implementados:

Page 6: Estrutura de Dados

  6  

3. Tamanho da Entrada

O tamanha da entrada é a quantidade de valores iniciais que serão implementados

e testados nos algoritmos. Dependendo do tipo ou estrutura do algoritmo, uma ordenação de

valores num algoritmo pode ser simples ou complexa, mostrando assim que devemos nos

preocupar em escolher melhor a estrutura para uma determinada quantidade de entrada. Em

alguns casos os algoritmos de ordenação mais simples terão uma maior eficiência que os

mais complexos, como o MergeSort que usa a recursividade em alguns problemas, e como

esta técnica tem um alto consumo de memória e tempo de execução, acaba não sendo muito

eficiente mesmo tendo uma complexidade de tempo menor (MergeSort Θ(n log2 n)). Mas

isso não significa que ele será mais eficiente que um InsertionSort, que tem sua

complexidade de tempo Θ (n2).

4. Tempo de Complexidade de um Algoritmo

4.1 Análise de Tempo

[ZIVIANI,2004] revela que uma das problemáticas que tem que ser resolvida pelo projetista é a questão da análise do tempo de execução de um dado algoritmo, que pode ser medido diretamente, apesar de ser considerada uma medida inadequada, por depender do compilador, do hardware, utilização de memória, serve para casos particulares, onde existem vários algoritmos para um mesmo problema. A forma mais adequada, seria o uso da função de complexidade, onde é possível ignorar o custo de algumas operações envolvidas, que venham a ser irrelevantes. Esta

Page 7: Estrutura de Dados

  7  

análise é importante, para desenvolver soluções mais rápidas, e que gastem menos recursos do computador, poupando memória por exemplo.

4.2 Análise do Pior, Médio e Melhor Casos

Segundo [MARCO, 2001] em sua dissertação, deixa transparecer que:

• Análise no pior caso.

Refere-se ao número máximo de operações fundamentais que devem ser feitas para a

resolução de qualquer problema do tamanho fixado.

Pode ser considerado como um limite de complexidade que não será ultrapassado, sendo

portanto, uma garantia de qualidade mínima do algoritmo. Sua desvantagem é que os casos

caóticos que dificilmente vão acontecer são levados em consideração, nessa análise.

• Análise no Caso Médio

É mais difícil de determinar do que a complexidade no pior caso. Porque baseia-se nas

distribuições probabilísticas dos dados de entrada do algoritmo, que nem sempre são

conhecidas. Esta análise é indicada para algoritmos que são utilizados com frequência.

Os algoritmos que não possuem nenhuma estrutura condicional apresentam complexidades

no pior caso e caso médio, iguais, porque será executada, sempre o mesmo número de

operações para um mesmo tamanho de entrada.

• Análise no melhor caso

De acordo com [ZIVIANI,2004], o melhor caso é dado a partir do menor tempo de

execução sobre todas as entradas de tamanho n.

4.3 Algoritmos de Ordenação

4.3.1 BubbleSort

É o método mais simples em termos de implementação, porém é o

menos eficiente. A idéia principal do algoritmo é percorrer o vetor n − 1 vezes, a cada

passagem fazendo flutuar para o início o menor elemento da sequência. Essa movimentação,

percorrendo o array fazendo comparações e trocas sucessivas lembra a forma como as

bolhas procuram seu pulam de um nível para o outro, por isso o nome do algoritmo.

Page 8: Estrutura de Dados

  8  

Seu uso não é recomendado para vetores com muitos elementos.

Este método pode ser melhorado devido à questão de que os

elementos nas posições acima ou iguais a n - i já estão na ordem correta depois da iteração i,

(ou seja cada iteração garante que pelo menos mais um elemento encontrou a posição

desejada)por isso eles não precisam ser considerados nas próximas iterações. Dessa maneira,

na primeira vez q o algoritmo percorre o array, só é feita a comparação entre os dois

primeiros elementos. [TENEBAUM, 1995]. O melhor caso quando utilizamos este método

se dá apenas quando o arquivo está completamente ordenado, fazendo n – 1 comparações e

nenhuma troca, percorrendo o array uma única vez. Encontramos o Pior caso quando o array

está em ordem reversa, ou seja, quando o késimo passo faz n - k comparações e trocas,

sendo necessário n – 1 passos.

Um dado curioso a cerca da ineficiência deste método acontece quando o array está

praticamente ordenado e apenas o menor dos elementos está na última posição. Desta

maneira o será realizado o mesmo número de comparações do pior caso.

4.3.2 InsertionSort

Segundo [QUEIROZ, 2009], a classificação por inserção é um método

in place que separa o vetor de entrada em dois subvetores, movendo os registros do subvetor

não-ordenado para o vetor ordenado, sendo o último acrescido de um elemento a cada

iteração. [ZIVIANI, 2004] comenta que em cada passo, a partir de i=2, o i-ésimo item do

vetor não-ordenado é apanhado e inserido no seu lugar apropriado dentro do vetor ordenado.

Page 9: Estrutura de Dados

  9  

Esse é um dos métodos mais utilizados entre os jogadores de cartas, por ser fácil de ser

implementado. A complexidade do algoritmo é da ordem O(n²) [ZIVIANI, 2004].

4.3.3 SelectionSort

De acordo com Ziviani, é um dos métodos de ordenação mais simples,

possui um tempo de execução linear no tamanho de entrada. Quando o arquivo já está

ordenado o custo é quadrático. É um método interessante para arquivos pequenos.

4.3.4 ShellSort

[ZIVIANI, 2004] explica que o shellsort é uma extensão do algoritmo

de ordenação por inserção. Entretanto, na classificação por inserção, se o menor item do

vetor de origem estiver na posição mais à direita, então o número de comparações e

movimentações é igual a (n-1) para encontrar o seu ponto de inserção.

A estratégia utilizada pelo shellsort para contornar este problema foi permitir trocas de

registros que estão distantes um do outro. Os itens que estão separados h posições são

rearranjados de tal forma que todo h-ésimo item leva a uma sequência ordenada.

Alguns autores chamam h de “salto”, que pode ser constante ou pode variar de acordo com

uma lógica previamente escolhida. Várias sequências para h têm sido experimentadas.

[KNUTH, 1973] mostrou experimentalmente que a escolha do incremento para h = {1, 4,

13, 40, 121, 364, 1093, 3280, ...} é difícil de ser batida por mais de 20% em eficiência no

tempo de execução.

Shellsort é uma ótima opção para arquivos de tamanho moderado (da ordem de 5000

registros), segundo ZIVIANI, tanto pela fácil implementação do código como pelo tempo de

classificação.

Quanto à sua complexidade, existem duas conjecturas tratadas por ZIVIANI: C(n) =

O(n1,25) e C(n) = O(n*log2(n)). O autor explica que o algoritmo possui em sua

complexidade problemas matemáticos difíceis de resolver e ninguém conseguiu prová-la

ainda.

4.3.5 QuickSort

Consiste em dividir o problema de ordenar um conjunto de n itens em

2 problemas menores, os problemas menores são ordenados e depois os resultados são

combinados para produzir a solução do maior problema. (Dividir para conquistar !) Este

método é ineficiente para arquivos já ordenados com pivô inadequado, pois as partições

Page 10: Estrutura de Dados

  10  

serão desiguais , e a função de ordenação será chamada n vezes, sendo que em cada uma

dessas só conseguirá eliminar um item por chamada, fazendo com que o número de

comparações passe a ser cerca de n2/2. O melhor caso acontece quando o arquivo é dividido

em duas partes iguais, este método requer uma pequena pilha, que servirá como memória

auxiliar, e ordenar um vetor com n itens, com cerca de nlog n operações.

4.3.6 MergeSort

O conceito de merging ou fundir é complementar ao conceito de

selecionar, visto anteriormente, quando se trata de algoritmos de ordenação. [SEDGEWICK,

1998] trata do termo como combinar dois arquivos [vetores] ordenados para formar um

maior que os anteriores também ordenado. Esse conceito faz parte da ideia de “dividir e

conquistar”, muito utilizado na ordenação de registros.

No caso do merge sort, a divisão é feita utilizando recursividade, armazenando os dados do

vetor original na pilha em forma de árvore binária, segundo [Queiroz, 2009]. Após a divisão,

cada subvetor ordenado é recombinado com outro intercalando os elementos, mantendo-se a

ordenação. Esse algoritmo é considerado de ordenação externa, pois se utiliza de outro

espaço da memória para efetuar a classificação.

[SEDGEWICK, 1998] ainda trata de alguns fatores que tornam o merge sort atrativo. Dentre

eles está o fato de que o tempo de execução para um vetor de n elementos é da ordem de

n*log(n). Outro fator observado pelo autor é que o algoritmo é estável, o que significa dizer

que independentemente do tamanho da entrada, a saída será sempre proporcional a n*log(n).

4.3.7 HeapSort

Utilizando o mesmo princípio do SelectSort, o HeapSort é um

algoritmo que utiliza uma estrutura de dados conhecida como Heap binário para manter o

próximo item a ser selecionado. Criado em 1964 por Robert W. Floyd e J.W.J. Williams, ele

é um algoritmo de Ordem de Complexidade O(n log n).

Existem dois tipos de heaps: Os heaps de máximo (max heap), em que

o valor de todos os nós são menores que os de seus respectivos pais; e os heaps de mínimo

(min heap), em que o valor de todos os nós são maiores que os de seus respectivos pais.

Assim, em um heap de máximo, o maior valor do conjunto está na raíz da árvore, enquanto

no heap de mínimo a raíz armazena o menor valor existente. Os heaps podem ser

representados por arranjos, nesse caso a maior (menor) chave está sempre na posição 1 do

array. Os algoritmos para implementar as operações sobre o heap operam ao longo de um

dos caminhos da árvore, a partir da raiz até o nível mais profundo da árvore.

Page 11: Estrutura de Dados

  11  

A figura abaixo mostra um exemplo de um HeapSort:

4.4 Comportamento das Funções de Tempo

[ZIVIANI,2004] Afirma que as funções de tempo são medidas a partir da

complexidade de um dado algoritmo, dadas pela notação do BIG O, cuja notação é definida

como um função g(n) O( f (n)) para alguma constante c > 0 a expressão 0 ≤ g(n) ≤ cf(n) é

válida.

As principais funções de complexidade:

• n f(n) = O(1)

Algoritmos de complexidade O(1) são ditos de complexidade constante.

• n f(n) = O(log n)

Um algoritmo de complexidade O(log n) é dito ter complexidade logarítmica.

Típico em algoritmos que transformam um problema em outros menores.

• n f(n) = O(n)

Um algoritmo de complexidade O(n) é dito ter complexidade linear

Cada vez que n dobra de tamanho, o tempo de execução dobra. n f(n) = O(n log n)

Page 12: Estrutura de Dados

  12  

Típico em algoritmos que quebram um problema em outros menores, resolvem cada um

deles independentemente e ajuntando as soluções depois.

• n f(n) = O(n2)

Um algoritmo de complexidade O(n2) é dito ter complexidade quadrática.

Ocorrem quando os itens de dados são processados aos pares, muitas vezes em um anel

dentro de outro.

• n f(n) = O(n3)

Um algoritmo de complexidade O(n3) é dito ter complexidade cúbica.

Úteis apenas para resolver pequenos problemas.

• n f(n) = O(2n)

Um algoritmo de complexidade O(2n) é dito ter complexidade exponencial.

Geralmente não são úteis sob o ponto de vista prático.

• n f(n) = O(n!)

Um algoritmo de complexidade O(n!) é dito ter complexidade exponencial,

apesar de O(n!) ter comportamento muito pior do que O(2n).

4.5 Análise Matemática e Empírica

Análise empírica baseia-se no desenvolvimento de uma implementação correta e

completa do algoritmo e depende não apenas da natureza dos dados de entrada utilizados

durante a experimentação, mas também de outros fatores que têm influência no

experimento. Como o ambiente de execução utilizado, considerando as máquinas, os

compiladores e os sistemas utilizados durante os experimentos. Enquanto que a análise

matemática é uma alternativa à análise empírica, sendo especialmente útil quando a análise

experimental consome uma quantidade significativa de tempo ou quando necessitamos de

alguma indicação de eficiência antes de qualquer investimento de desenvolvimento.

De acordo com [SEDGEWICK,1998], ele comenta que a análise matemática pode

trazer mais informações e ser mais barata que a análise empírica, que em alguns casos pode

ser suficiente.

Page 13: Estrutura de Dados

  13  

Com a metodologia utilizada, espera-se obter o tempo médio da ordenação de um conjunto

de entradas, aplicado aos algoritmos analisados. Assim poderemos comparar a praticidade

com que os algoritmos podem ser utilizados. Devido ao experimentos iniciais de duração

prolongada, foram criados dois conjuntos de entradas para serem executados pelos

algoritmos “eficientes” e pelos “menos eficientes”.

Os algoritmos foram subdivididos em dois grupos: 1 – Bubble, Selection e Insertion.

2 – Quick, Merge, Heap e Shell.

Paro o grupo 1, foi utilizado o seguinte conjunto de entradas em elementos int: 30.000;

60.000;120.000;240.000;480.000 e 960.000

Paro o grupo 2, foi utilizado o seguinte conjunto de entradas em elementos int: 30.000;

60.000;120.000;240.000;480.000;960.000 e 2.000.000

4.6 Gráficos do Melhor, Médio e Pior casos

Page 14: Estrutura de Dados

  14  

Page 15: Estrutura de Dados

  15  

Page 16: Estrutura de Dados

  16  

4.7 Conclusões sobre análise empírica e matemática

Podemos concluir que à medida que o número de elementos aumenta, o

desempenho diminui e o tempo em milissegundos, aumenta. Tomando “N” como o tamanho

do vetor, com exceção dos métodos, no melhor caso, BubbleSort que verifica se o seu

sucessor é maior, e o InsertionSort que verifica se seu antecessor é menor, N-1 vezes.

O método que no geral, apresentou o melhor desempenho, foi o ShellSort.

4.8 Limite Inferior e Limite Superior

O limite superior de complexidade diz respeito ao melhor algoritmo conhecido que o resolva. Enquanto o limite inferior de complexidade diz respeito a quantidade mínima necessária de recursos para a resolução do problema.

4.9 Eficiência dos Algoritmos

Cada autor tem seu próprio conceito do que é um algoritmo, mais podemos

resumir todos estes conceitos em um, algoritmo nada mais é do que uma receita que mostra

passo a passo os procedimentos necessários para a resolução de uma tarefa. Em termos mais

técnicos, um algoritmo é uma sequência lógica, finita e definida de instruções que devem ser

seguidas para resolver um problema ou executar uma tarefa, e com isso vem outra questão,

podem existir inúmeros tipos diferentes de procedimentos que levem a resolução de um

mesmo problema, cada procedimento terá uma complexidade e um tempo de duração para

se chegar ao objetivo, ou seja, cada algoritmo tem sua sequência própria de passos e seu

tamanho. Quando levamos em conta as questões como o armazenamento de dados e

Como podemos definir se um algoritmo é melhor que o outro assumindo que todos sejam

eficazes, devemos então verificar qual é o mais eficiente. Eficiência pode ser definida como

a capacidade de se atingir um resultado correto, utilizando a menor quantidade de recursos e

tempo possível. Uma das formas de se analisar o tempo de execução de um algoritmo é

conhecida como análise assintótica, ou cálculo da eficiência assintótica, em que se procura

encontrar uma tendência no tempo de execução, quando o volume de dados de entrada do

problema tende ao infinito. Todos esses conjuntos de ferramentas de análise fazem parte de

uma área de conhecimento que visa não apenas entender as limitações dos algoritmos, mas

também melhorar a qualidade e a eficiência do software desenvolvido. Todo desenvolvedor

deveria saber utilizar corretamente estas ferramentas e organiza-los de forma coerente,

mostramos que estamos preocupados com o melhor

Page 17: Estrutura de Dados

  17  

se estes dados estão no caminho para se chegar ao objetivo, que é o jeito mais rápido e fácil

de se resolver um problema. Existem vários tipos de estruturas e nenhuma delas funciona

bem para todos os propósitos, e com isso é importante não só conhecer cada uma delas mais

também escolher aquela que irá proporcionar um melhor desempenho.

O tipo de estrutura a ser utilizada em um algoritmo está relacionado principalmente

com o tamanho de sua entrada, um exemplo disso é o tipo de ordenação que será

utilizada em uma lista, dependendo do tamanho de itens a serem inseridos na lista a

ordenação poderá ser simples, como exemplo o Insertion sort, Selection sort ou

Bubble sort, ou uma ordenação mais complexa como o Quick sort ou Merge sort,

em certos casos os algoritmos de ordenação mais simples terão uma maior eficiência que os

mais complexos, como o Merge sort usa a recursividade em alguns

problemas e está técnica não é muito eficiente devido ao alto consumo de memória e

tempo de execução, mesmo tendo uma complexidade de tempo menor(Merge sort

Θ(n log2 n)) não significa que ele será mais eficiente que o Insertion sort que tem a

complexidade de tempo Θ (n2).

Um dos motivos para se preocupar com a melhor estrutura a ser utilizada em um

certo problema é que os computadores têm suas limitações, por mais que os

computadores atuais pareçam rápidos e sua memória seja absurdamente grande,

certas tarefas levam muito tempo para serem executadas, imagine um computador

que fosse infinitamente rápido, você não precisaria se preocupar com a estrutura que

escolheu para solucionar seu problema e assim todos os algoritmos capazes de

resolver uma tarefa teriam resultados iguais, assim utilizaríamos sempre o método

mais fácil de ser implementado, já que esse computador não existe e nunca vai

existir é de extrema importância criar algoritmos eficientes em termos de tempo e de

espaço alocado na memória para assim termos os melhores resultados possíveis.

5. Espaço de Complexidade de um Algoritmo

Existem dois tipos de utilização de espaço extra, o primeiro é quando os

elementos a serem ordenados excedem o tamanho da memória principal, e o segundo é

quando necessitamos de um espaço, como por exemplo, um vetor extra definido pelo

próprio algoritmo, para possibilitar a realização das operações.

Page 18: Estrutura de Dados

  18  

No nosso caso, não foi utilizado o primeiro tipo (ordenação externa), e o segundo foi

utilizado paraos métodos de ordenação MergeSort e QuickSort.

6. Conclusão

De forma resumida, podemos concluir que, apesar de alguns algoritmos serem

mais eficientes que outros, em um caso especifico podemos mudar esta percepção, no

melhor caso, o BubbleSort tem um melhor desempenho que o QuickSort ou ShellSort. E o

ShellSort, ao observar o comportamento de tempo de execução, o ShellSort é o mais

eficiente.

A partir da análise matemática e empírica é possível analisar para qualquer caso o algoritmo

mais adequado. Após a conclusão deste relatório, seremos capazes de nos preocupar em

poupar memória, e fazer um algoritmo mais eficiente e cada vez mais profissional.

7. Referências Bibliográficas

1. SEDGEWICK, Robert, 1946 Algoriths in C / Robert Sedgewick – 3rd ed. – Reading,

Mass.: Addison Wesley, c1998.

2. TENEMBAUM, Aaron M., LAMNGSAM, Yedidyah, AUGENSTEIN, Mosha J.;

estruturas de dados Usando C, Pearson Makron Books, 2005.

3. ZIVIANI, Nívio, 2004 Projetos de Algoritmos.

4. QUEIROZ, Ana E., Notas de aula, 2009.