Análise de Algoritmos Parte 4

Documentos relacionados
Bruno Hott Algoritmos e Estruturas de Dados I DECSI UFOP. Recursividade

Recursividade. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR

ALGORITMOS AVANÇADOS UNIDADE II Recursividade. Luiz Leão

Recursividade. Prof. Jesus José de Oliveira Neto

Estruturas de Dados, Análise de Algoritmos e Complexidade Estrutural. Carlos Alberto Alonso Sanches

Análise de Problemas Recursivos. Algoritmos e Estruturas de Dados Flavio Figueiredo (

Recursividade. Objetivos do módulo. O que é recursividade

SCC Capítulo 2 Recursão

Ordenação: QuickSort. Prof. Túlio Toffolo BCC202 Aula 15 Algoritmos e Estruturas de Dados I

Técnicas de análise de algoritmos

Introdução à Ciência da Computação II. Recursão. Prof. Ricardo J. G. B. Campello

Recursão. Aula 1. Liana Duenha. Faculdade de Computação Universidade Federal de Mato Grosso do Sul

Universidade Federal de Uberlândia Faculdade de Computação. Linguagem C: funções

Construção de Algoritmos II Aula 06

Solução de Recorrências

Análise e Complexidade de Algoritmos

Revisão: Tipo Abstrato de Dados Recursividade

Recursividade. Métodos iterativos. Prof. Cesar Augusto Tacla. Métodos iterativos utilizam estruturas de repetição

BCC202 - Estrutura de Dados I

Análise de Algoritmos

Aula 06: Análise matemática de algoritmos recursivos

Algoritmos Avançados Análise de Complexidade

Programação Estruturada

Lista de Exercícios sobre Recursividade

Área que visa determinar a complexidade (custo) de um algoritmo, com isso é possível:

Introdução à Análise Algoritmos

Algoritmos e Estruturas de Dados I

Teoria da Computação. Aula 3 Comportamento Assintótico 5COP096. Aula 3 Prof. Dr. Sylvio Barbon Junior. Sylvio Barbon Jr

CES-11. Noções de complexidade de algoritmos. Complexidade de algoritmos. Avaliação do tempo de execução. Razão de crescimento desse tempo.

Roteiro Prático Nº 13 Recursividade

Quantidade de memória necessária

SCC0601 Projeto de Algoritmos. Recursão

Pesquisa e Ordenação

Recursividade, Tentativa e Erro

UNIVERSIDADE FEDERAL RURAL DO SEMI-ÁRIDO CURSO: CIÊNCIA DA COMPUTAÇÃO. Prof.ª Danielle Casillo

Medida do Tempo de Execução de um Programa. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR

Recursividade. Túlio Toffolo BCC202 Aula 08 Algoritmos e Estruturas de Dados I

COMPLEXIDADE DE ALGORITMOS

BCC202 - Estrutura de Dados I

Análise de Complexidade para algoritmos iterativos e recursivos

Módulo 7. Funções. Algoritmos e Estruturas de Dados I C++ (Rone Ilídio)

INF 1010 Estruturas de Dados Avançadas

Centro Federal de Educação Tecnológica de Minas Gerais Programa de Pós-Graduação em Modelagem Matemática e Computacional

ANÁLISE DE ALGORITMOS: PARTE 4

Introdução Paradigmas

Permite modularidade (dividir programa em partes): Facilita a depuração (debug) e portabilidade.

É interessante comparar algoritmos para valores grandes de n. Para valores pequenos de n, mesmo um algoritmo ineficiente não custa muito para ser

Projeto e Análise de Algoritmos Aula 4: Dividir para Conquistar ou Divisão e Conquista ( )

Complexidade de Algoritmos

Relações de recorrência

Análise de Algoritmos

Projeto e Análise de Algoritmos

Algoritmos de Ordenação

BCC202 - Estrutura de Dados I

ALGORITMOS AVANÇADOS UNIDADE I Análise de Algoritmo - Notação O. Luiz Leão

Técnicas de projeto de algoritmos: Indução

PROGRAMAÇÃO DE COMPUTADORES V - TCC Modulo 6 : Funções Escopo de Variáveis: Globais x Locais Aura - Erick

Paradigmas de Projeto de Algoritmos

LINGUAGEM C: FUNÇÕES FUNÇÃO 04/07/2017. Funções são blocos de código que podem ser nomeados e chamados de dentro de um programa.

2. Complexidade de Algoritmos

04 Recursão SCC201/501 - Introdução à Ciência de Computação II

Aula 05: - Recursão (parte 1)

SCC Capítulo 6 Paradigmas e Técnicas de Projetos de Algoritmos

COMPLEXIDADE DE ALGORITMOS COMPLEXIDADE DE ALGORITMOS

Recursividade. Recursividade

Aula prática 5. Funções Recursivas

Paradigmas de Projetos de Algoritmos

Técnicas de projeto de algoritmos: Indução

ANÁLISE DE ALGORITMOS: PARTE 3

Recursividade. Estrutura de Dados. Prof. Kleber Rezende

Análise de Complexidade de Algoritmos. mario alexandre gazziro

Transcrição:

Análise de Algoritmos Parte 4 Túlio Toffolo tulio@toffolo.com.br www.toffolo.com.br BCC202 Aula 07 Algoritmos e Estruturas de Dados I

Como escolher o algoritmo mais adequado para uma situação? (continuação)

Mais sobre notação assintótica de funções Existem duas outras notações na análise assintótica de funções: Notação o ( O pequeno) Notação ω Estas duas notações não são usadas normalmente, mas é importante saber seus conceitos e diferenças em relação às notações O e Ω, respectivamente 3

Notação o O limite assintótico superior definido pela notação O pode ser assintoticamente firme ou não: Por exemplo, o limite 2n 2 = O(n 2 ) é assintoticamente firme, mas o limite 2n = O(n 2 ) não é. A notação o é utilizada para definir um limite superior que não é assintoticamente firme Matematicamente, g(n) é o(f(n)) se: Existem duas constantes positivas c e m tais que, para n m, temos g(n) < c f(n). 4

Notação ω De forma análoga, a notação ω está relacionada com a notação Ω, da mesma maneira, ou seja: A notação ω é utilizada para definir um limite inferior que não é assintoticamente firme Matematicamente, g(n) é ω (f(n)) se: Existem duas constantes positivas c e m tais que, para n m, temos g(n) > c f(n). 5

Hierarquia de Funções A seguinte hierarquia pode ser definida do ponto de vista assintótico: 1 log log n log n n n c n log n c n n n c cn onde ε e c são constantes com 0 < ε < 1 < c. 6

Problema do Caixeiro Viajante Seja um conjunto de cidades e uma matriz de distâncias entre elas PCV consiste em encontrar uma rota para um Caixeiro Viajante tal que este: parta de uma cidade origem passe por todas as demais cidades uma única vez retorne à cidade origem ao final do percurso percorra a menor distância possível Esta rota é conhecida como ciclo hamiltoniano

Problema do Caixeiro Viajante

Problema do Caixeiro Viajante

Recursividade Parte 1 Túlio Toffolo tulio@toffolo.com.br www.toffolo.com.br BCC202 Aula 07 Algoritmos e Estruturas de Dados I

Recursividade A recursividade é uma estratégia que pode ser utilizada sempre que uma função f pode ser escrita em função dela própria. Exemplo Função fatorial: n! = n * (n-1) * (n-2) * (n-3) *...* 1 (n-1)! = (n-1) * (n-2) * (n-3) *...* 1 logo: n! = n * (n-1)!

Recursividade Definição: dentro do corpo de uma função, chamar novamente a própria função Recursão direta: a função A chama a própria função A Recursão indireta: a função A chama uma função B que, por sua vez, chama A

Condição de parada Nenhum programa nem função pode ser exclusivamente definido por si Um programa seria um loop infinito Uma função teria definição circular Condição de parada Permite que o procedimento pare de se executar Exemplo: f(x) > 0 onde x é decrescente Objetivo Estudar recursividade como ferramenta prática!

Recursividade Para cada chamada de uma função, recursiva ou não, os parâmetros e as variáveis locais são empilhados na pilha de execução. No que isto implica? Maior consumo de memória!

Execução Internamente, quando qualquer chamada de função é feita dentro de um programa, é criado um Registro de Ativação na Pilha de Execução do programa O registro de ativação armazena os parâmetros e variáveis locais da função bem como o ponto de retorno no programa ou subprograma que chamou essa função. Ao final da execução dessa função, o registro é desempilhado e a execução volta ao subprograma que chamou a função

Exemplo int fat1(int n) { int r; if (n<=0) r = 1; else r = n*fat1(n-1); return r; void main() { int f; f = fatx(4); printf("%d",f); int fat2(int n) { if (n<=0) return 1; else return n * fat2(n-1);

Complexidade A complexidade de tempo do fatorial recursivo é O(n). (Em breve iremos ver a maneira de calcular isso usando equações de recorrência). Mas a complexidade de espaço também é O(n), devido a pilha de execução. Ja no fatorial não recursivo a complexidade de espaço é O(1). Fat (int n) { int f = 1; while(n > 0){ f = f * n; n = n 1; return f;

Recursividade Portanto, a recursividade nem sempre é a melhor solução, mesmo quando a definição matemática do problema é feita em termos recursivos Além disso, pode-se afirmar que: Todo algoritmo recursivo tem uma versão nãorecursiva O que devemos nos perguntar é: vale a pena implementar esta versão não-recursiva?

Fibonacci Outro exemplo: Série de Fibonacci: F n = F n-1 + F n-2 n > 2, F 0 = 0 F 1 = 1 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89... int Fib(int n) { if (n<=0) return 0; else if ( n == 1) return 1; else return Fib(n-1) + Fib(n-2);

Fibonacci não recursivo int FibIter(int n) { int i, k, F; i = 1; F = 0; for (k = 1; k <= n; k++) { F += i; i = F - i; return F; Complexidade: O(n) Conclusão: não usar recursividade cegamente!

Análise da função Fibonacci Ineficiência em Fibonacci Termos F n-1 e F n-2 são computados independentemente Número de chamadas recursivas = número de Fibonacci! Custo para cálculo de F n O(φ n ) onde φ = (1 + 5)/2 = 1,61803... Golden ratio Exponencial!!!

Fibonacci recursivo melhorado int FibR(int n, int a, int b) { if (n == 0) return a; if (n == 1) return b; return FibR(n-1, b, a+b); int Fib(int n) { return FibR(n, 0, 1);

Quando vale a pena usar recursividade Recursividade vale a pena para Algoritmos complexos, cuja a implementação iterativa é complexa e normalmente requer o uso explícito de uma pilha Dividir para Conquistar (Ex. Quicksort) Caminhamento em Árvores (pesquisa, backtracking)

Dividir para Conquistar Duas chamadas recursivas Cada uma resolvendo a metade do problema Muito usado na prática Solução eficiente de problemas Decomposição Não se reduz trivialmente como fatorial Duas chamadas recursivas Não produz recomputação excessiva como fibonacci Porções diferentes do problema

Exemplo simples: régua int regua(int l,int r,int h) { int m; if ( h > 0 ) { m = (l + r) / 2; marca(m, h); regua(l, m, h 1); regua(m, r, h 1); Qual é a ordem de impressão das marcas?

Execução: régua regua(0, 8, 3) marca(4, 3) regua(0, 4, 2) marca(2, 2) regua(0, 2, 1) marca(1, 1) regua(0, 1, 0) regua(1, 2, 0) regua(2, 4, 1) marca(3, 1) regua(2, 3, 0) regua(3, 4, 0) regua(4, 8, 2) marca(6, 2) regua(4, 6, 1) marca(5, 1) regua(4, 5, 0) regua(5, 6, 0) regua(6, 8, 1) marca(7, 1) regua(6, 7, 0) regua(7, 8, 0)

Outra implementação: régua int regua2(int l,int r,int h) { int m; m = (l + r) / 2; marca(m,h); if ( h > 1 ) { regua(l, m, h 1); regua(m, r, h 1);

Outra implementação: régua int regua(int l,int r,int h) { int m; if ( h > 0 ) { m = (l + r) / 2; marca(m, h); regua(l, m, h 1); regua(m, r, h 1); int regua2(int l,int r,int h) { int m; m = (l + r) / 2; marca(m,h); if ( h > 1 ) { regua(l, m, h 1); regua(m, r, h 1);

Perguntas?

Exercício Crie uma função recursiva que calcula a potência de um número: Como escrever a função para o termo n em função do termo anterior? Qual a condição de parada?