Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar...

27
Programação I Aula 16 — Mais exemplos de recursão Pedro Vasconcelos DCC/FCUP 2018 Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 1 / 27

Transcript of Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar...

Page 1: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Programação IAula 16 — Mais exemplos de recursão

Pedro Vasconcelos

DCC/FCUP

2018

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 1 / 27

Page 2: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Nesta aula

1 Desenhar árvores

2 Sequência de Fibonnacci

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 2 / 27

Page 3: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Desenhar árvores

Vamos fazer uma função recursiva para desenhar árvores usandoturtle graphics.

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 3 / 27

Page 4: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Desenhar árvores (cont.)

Parameterizamos a árvore pelo número de bifurcações n.

Para desenhar uma árvore de ordem n:1 desenhamos o tronco;2 rodamos à esquerda e desenhamos uma árvore de ordem n − 1;3 rodamos à direita e desenhamos outra árvore de ordem n − 1.

Entre os passos 2 e 3 devemos repor a posição e orientação datartaruga.

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 4 / 27

Page 5: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Desenhar árvores (cont.)

Mais alguns parâmetros:

size tamanho em pixelsratio fração de tamanho do

troncoangle ângulo de rotação

para as sub-árvores

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 5 / 27

Page 6: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Em Python

def draw_tree(n, angle, ratio, size):forward(ratio*size) # desenhar uma linhaif n>0: # caso recursivo

nsize = (1-ratio)*size(x,y) = position() # guardar posiçãoh = heading() # e orientaçãoleft(angle)draw_tree(n-1, angle, ratio, nsize)penup() # não desenhargoto(x,y) # repor a posiçãosetheading(h) # e orientaçãopendown() # voltar a desenharright(angle)draw_tree(n-1, angle, ratio, nsize)

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 6 / 27

Page 7: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Exemplos: draw_tree(6, . . . )

angle = 30 angle = 60 angle = 90

ratio

=0.

3ra

tio=

0.5

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 7 / 27

Page 8: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Extras

Exercícios da folha 9:Mudar a cor de ramos e a espessura do traço conforme o nível nUsar random para escolher o ângulo e/ou redução do tamanhode ramos aleatoriamente

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 8 / 27

Page 9: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Nesta aula

1 Desenhar árvores

2 Sequência de Fibonnacci

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 9 / 27

Page 10: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Sequência de Fibonnacci

Conhecida na Índia (700 DC)Introduzida na Europa por Leonardo de Pisa (1202 DC)Modelo simplificado do crescimento de uma população:

um par de coelhos são largados num campo;os coelhos podem acasalar com um mês;no fim do segundo mês, nasce um novo par de coelhos;os coelhos não morrem e cada par produz sempre um novo par aofim de um mês.

Quantos pares de coelhos existem ao fim de um ano?

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 10 / 27

Page 11: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Sequência de Fibonnacci

mês 0 1 2 3 4 5 6 7 . . .pares 1 1 1 + 1︸ ︷︷ ︸

=2

1 + 2︸ ︷︷ ︸=3

2 + 3︸ ︷︷ ︸=5

3 + 5︸ ︷︷ ︸=8

5 + 8︸ ︷︷ ︸=13

8 + 13︸ ︷︷ ︸=21

. . .

Inicialmente há 1 parAo fim de 1 mês o par acasalou (mas ainda há só 1 par)Ao fim de 2 meses nasce um novo parAo fim de 3 meses, nascem 2 pares (da primeira e segundafêmea)Ao fim de 4 meses, nascem 3 pares. . .Depois dois valores iniciais, cada número é a soma dos doisimediatamente anteriores

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 11 / 27

Page 12: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Recorrência

O n-ésimo número de Fibonnacci Fn é dado pela seguinte relação derecorrência:

F0 = 1F1 = 1Fn = Fn−1 + Fn−2 (n > 1)

Vamos usar esta relação para calcular a sequência de Fibonnacci comuma função recursiva em Python.

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 12 / 27

Page 13: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Implementação recursiva

def fib(n):"Calcular o n-ésimo número de Fibonnaci."if n == 0 or n == 1: # caso base

return 1else: # caso recursivo

return fib(n-1) + fib(n-2)

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 13 / 27

Page 14: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Testando a implementação

Vamos testar esta função imprimindos os primeiros 100 valores dasequência.

print("n", ":", "F_n")for n in range(100):

print(n, ":", fib(n))

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 14 / 27

Page 15: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Testando a implementação (cont.)

n : F_n0 : 11 : 12 : 23 : 34 : 55 : 86 : 137 : 21...

30 : 134626931 : 217830932 : 352457833 : 5702887KeyboardInterrupt

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 15 / 27

Page 16: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Testando a implementação (cont.)

Os resultado estão corretos mas o cálculo demora cada vez maistempo à media que n aumenta

A partir de n ≈ 30 demora vários segundos por cada novo valor

Esta implementação é pouco eficiente!

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 16 / 27

Page 17: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Eficiência

Vamos fazer um gráfico do tempo de computação em função de n

Começamos por gerar um ficheiro de texto com a tabela queassocia a cada n o tempo de computação de fib(n)

Para obter tempos usamos a bibloteca time (permite acesso aorelógio interno do computador)

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 17 / 27

Page 18: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Eficiência (cont.)

import timef = open("fib_time.txt", "w")for n in range(40):

t0 = time.clock() # relógio inicialfn = fib(n)t1 = time.clock() # relógio final# a diferença entre os valores do relógio# dá-nos o tempo do cálculo (em segundos)delta = t1 - t0f.write("%d\t %f\n" % (n,delta))

f.close()

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 18 / 27

Page 19: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Eficiência (cont.)Para traçar o gráfico vamos usar o utilitário GNUplot:

gnuplot> plot("fib_time.txt")

0

5

10

15

20

25

30

35

40

45

0 5 10 15 20 25 30 35 40

CPU

tim

e

n

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 19 / 27

Page 20: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Análise

Para cada n > 1 necessitamos de resolver dois sub-problemas detamanho n − 1 e n − 2O tempo T (n) de cálculo de fib(n) satisfaz

T (n) = · · ·+ T (n − 1) + T (n − 2)

A solução desta recorrência é uma função exponencial em nPodemos evitar o crescimento exponencial evitando cálculosdesnecessários

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 20 / 27

Page 21: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Cálculos desnecessários

Exemplo: calcular fib(4)

fib(4)= fib(3) + fib(2)= (fib(2) + fib(1)) + fib(2)= (fib(2) + fib(1)) + (fib(1) + fib(0))= ((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))

O cálculo de fib(2) é repetido desnecessariamenteSempre que calculamos fib(n) temos de calcular todosinferiores a n

Ideia: guardar valores já calculados para evitar repetir trabalho

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 21 / 27

Page 22: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Fibonacci com memorização

Vamos usar um dicionário global para guardar resultadospreviamente calculados

Inicialmente o dicionário começa vazio

No inicio da função testamos se o valor já foi calculo e retornamosimediamente nesse caso

Após calcular um novo valor guardamos no dicionário

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 22 / 27

Page 23: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Fibonacci com memorização (cont.)

fib_memo = {} # inicialização do dicionário

def fastfib(n):"Calcular o n-ésimo Fibonnacci c/memorização."# verificar se o resposta já foi calculada# e nesse retorná-la imediatamenteif n in fib_memo:

return fib_memo[n]# caso contrário, calcular como anteriormenteif n == 0 or n == 1:

r = 1else:

r = fastfib(n-1) + fastfib(n-2)# memorizar a resposta e retornarfib_memo[n] = rreturn r

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 23 / 27

Page 24: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Observações

O dicionário fib_memo foi declarado fora da funçãoDeve ser uma variável global para que os valores memorizadospersistam depois do retorno da funçãoPor exemplo: depois de calcular fib(10) o dicionário vai contertodos os valores de fib(0) até fib(10)

>>> fib_memo{}>>> fastfib(10)89>>> fib_memo{1: 1, 0: 1, 2: 2, 3: 3, 4: 5, 5: 8,6: 13, 7: 21, 8: 34, 9: 55, 10: 89}

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 24 / 27

Page 25: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Observações (cont.)

Com memorização conseguimos calcular Fibonnacci para n muitomaiores praticamente instantaneamente:

>>> fastfib(40)165580141>>> fastfib(500)225591516161936330872512695036072072046011324913758190588638866418474627738686883405015987052796968498626

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 25 / 27

Page 26: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Solução iterativa

Podemos também calcular números de Fibonnacci de formaiterativa (i.e. sem recursão)

Depois dos dois primeiros valores cada número é a soma dosanteriores

Ideia: basta guardar os dois números anteriores para calcular oseguinte

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 26 / 27

Page 27: Programação I Aula 16 Mais exemplos de recursãopbv/aulas/programacaoI/teorica-16.pdf · Usar random para escolher o ângulo e/ou redução do tamanho de ramos aleatoriamente Pedro

Solução iterativa (cont.)

def iterfib(n):# dois valores seguidos na sequência# inicialmente fib(0)=1, fib(1)=1v0 = 1v1 = 1# repetir n-1 vezesfor i in range(n-1):

v0, v1 = v1, v0+v1return v1

Esta solução é eficiente e não necessita de guardar todos os valoresjá calculados.

Pedro Vasconcelos (DCC/FCUP) Programação I Aula 16 — Mais exemplos de recursão 2018 27 / 27