26
20 Outubro 2 005 Funções, Execução Condicional, Recursividade e Iteração 1 Funções, Execução Condicional, Recursividade e Iteração Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

Embed Size (px)

Citation preview

Page 1: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 1

Funções, Execução Condicional, Recursividade e Iteração

Jorge CruzDI/FCT/UNL

Introdução aos Computadores e à Programação1º Semestre 2005/2006

Page 2: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 2

Programas e Funções• Como foi visto no exemplo anterior, um programa pode ser

considerado como o encadeamento de diversas funções, isto é, no corpo de uma função são chamadas outras funções.

• Um programa pode pois ser estruturado de forma a ser composto por várias funções, tal como é feito na “matemática”. Por exemplo,

tg(x) = sin(x) / cos(x).

• Em algumas linguagens de programação, em vez de funções são usados procedimentos, mas a filosofia de encadeamento é semelhante.

• De notar que o programa principal, pode ele próprio ser visto como uma função.

Page 3: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 3

Funções Recursivas• Um caso particular ocorre quando as funções se chamam a si

próprias, isto é, quando as funções são recursivas.

• Talvez o exemplo mais simples seja o da função factorial, que pode ser definida (incompletamente) como

fact(n) = n * fact(n-1)

• Nestas condições, tal como nos ciclos, levanta-se o problema da terminação. Se uma função se chama a si própria, existe o risco de a computação se tornar infinita (entrar em ciclo fechado ou “loop”).

• É pois condição necessária para evitar estes ciclos infinitos que sejam definidas e testadas em primeiro lugar as condições de fim da recursividade.

Page 4: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 4

Funções Recursivas• Em geral, a recursividade é feita com base num conjunto

recursivo (indutivo), definido através de cláusulas– de base; um ou vários elementos de base (que fecham a recursão)

– de recursão: uma definição recursiva que permite a obtenção de elementos a partir de outros elementos.

• Num grande número de casos, o conjunto recursivo utilizado é o conjunto dos numeros inteiros, em que

– 1 (ou 0) é um número inteiro (cláusula de base)

– Se i é inteiro, i+1 também é inteiro (cláusula de recursão)

• Tendo em conta esta estrutura recursiva, podemos definir (correctamente) a função factorial tendo em conta a cláusula de base e a cláusula recursiva:

010

nse)n(fact*nnsen

)n(fact

Page 5: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 5

Execução Condicional• Quando queremos, como no caso do factorial, que um

programa execute uma de duas alternativas, dependendo do valor de uma condição, deve ser usada a instrução “se”:

• Em Condição deve estar uma expressão cujo resultado ou é verdadeiro ou é falso (para que, em tempo de execução, se possa decidir qual a alternativa a executar)

• As expressões cujo resultado pode ser verdadeiro ou falso chamam-se Expressões Booleanas.

se Condição então% alternativa a executar quando a condição for

verdadeira senão % alternativa a executar quando a condição for falsafim se;

Page 6: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 6

Expressões Booleanas

• Expressões booleanas podem ser construidas recursivamente a partir de outras mais simples com os operadores booleanos de

– Conjunção, “e” ou “and”, expressa como & em OCTAVE

– Disjunção, “ou” ou “or”, expressa como | em OCTAVE

– Negação, “não” ou “not”, expressa como ! em OCTAVE

• As variáveis booleanas podem tomar os valores verdade ou falso. Em OCTAVE, que só considera variáveis “numéricas”, 0 corresponde a falso e qualquer outro valor a verdade!

• De notar que uma variável booleana pode ser atribuído o valor booleano de uma comparação numérica. Por exemplo:

encontrada = (x > xmin & y > ymax)

Page 7: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 7

Função Factorial• A função factorial pode ser definida (em pseudo-código) como

função fact(n) se n = 0 então % elemento base fact 1 senão % definição recursiva fact n * fact(n-1) fimse; fimfunção;

• Em Octave, a definição é semelhante

function f = fact(n); if n == 0 % elemento base f = 1 else % definição recursiva f = n * fact(n-1) endif; endfunction;

Page 8: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 8

Limites à Recursividade• De notar que para prevenir os ciclos infinitos, o Octave tem

uma variável prédefinida, max_recursion_depth, que limita o número de chamadas recursivas de uma função.

• Por omissão (“default”), o valor da variável é 256, pelo que não se pode calcular fact(260) sem alterar o valor da variável.

• Existem várias outras funções recursivas em que pode existir mais do que um elemento base ou em que o conjunto recursivo é mais difícil de definir. Em qualquer caso é essencial definir a condição de terminação.

• Para exemplificar estas funções, estudamos de seguida – a determinação dos números de Fibonacci e – o cálculo do maior divisor comum entre dois números.

Page 9: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 9

Função Fibonacci (Recursiva)• Fibonacci (matemático da Renascença italiana) estabeleceu uma

série curiosa de números para modelar o número de casais de coelhos em sucessivas gerações. Em cada geração, o número pode ser obtido através dos das 2 gerações anteriores através de

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

• Assumindo que nas primeiras duas gerações só existe um casal de coelhos, os sucessivos números de Fibonacci são

1,1,2,3,5,8,13,21,34,55,89, ...

• Estes números ocorrem em vários processos biológicos (e não só), por exemplo, no número de pétalas de algumas flores.

• A sua determinação recursiva impõe o cálculo directo do valor para 2 elementos de base (a 1ª e a 2ª geração).

Page 10: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 10

Função Fibonacci (Recursiva)• Em Octave, a definição do números de Fibonacci pode ser

feita muito facilmente como function f = fib(n); if n == 1 % 1º elemento base f = 1; elseif n == 2 % 2º elemento base f = 1; else % definição recursiva f = fib(n-1) + fib(n-2); endif; endfunction;

• Como é fácil de constatar, se o número n inicial for maior ou igual a 1, a recursão termina. No entanto, se se chamar fib(0) a computação não termina (em Octave termina quando o número de chamadas recursivas exceder o valor da variável max_recursion_depth)!

Page 11: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 11

Função Máximo Divisor Comum (Recursiva)• Como se sabe, o máximo divisor comum (mdc) entre dois

números m e n é também um divisor da sua diferença, m-n. Por exemplo, o mdc de 60 e 36 é 12, que divide 24 = 60-36.

• Por outro lado, o mdc dos dois números m e n é ainda o mdc do menor número (n) com a diferença (m-n). Se houvesse um divisor comum maior, ele seria igualmente divisor de n, contrariamente à hipótese.

• Assim, pode determinar-se o mdc de dois números através da determinação do mdc de números cada vez menores. A computação termina quando os números forem iguais, caso em que o mdc é esse número.

• Por exemplo: 60-36 =24 ; 36-24=12; 24-12=12; 12 = 12 !

Page 12: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 12

Função Máximo Divisor Comum (Recursiva)• Em Octave, pode determinar-se o maior divisor comum de dois

números com a função seguinte function d = mdc(m,n); if m == n d = m; else if m-n >= n d = mdc(m-n,n); else d = mdc(n,m-n); endif; endif; endfunction;

• De notar que na chamada, o 1º argumento (m) é sempre maior ou igual que o 2º (n), de forma a garantir que m-n seja positivo!

Page 13: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 13

Recursividade para Resolução de Problemas• A recursividade pode ser usada na resolução de problemas,

difíceis de resolver por outras técnicas de programação.

• Tal é o caso das “Torres de Hanoi”: dadas três torres (estacas) pretende-se passar uma “pirâmide” de peças ordenadas de uma torre para outra, movendo-se uma peça de cada vez, para o topo de uma torre encimada por uma peça menor.

Page 14: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 14

• Apesar de aparentemente complicado, este problema tem uma solução recursiva simples.

• Para passar n peças de uma torre (A) para outra (C)1. Passar n-1 peças da torre inicial (A) para a torre livre

(B)2. Mover a última peça, para a torre final (C)3. Passar as n-1 peças da torre B para a torre final (C).

Torres de Hanoi - Recursividade

Page 15: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 15

Torres de Hanoi: Movimentos Necessários

• Baseados nesta resolução recursiva podemos

– Determinar o número de movimentos necessários

– Determinar os movimentos necessários

• O número de movimentos necessários é bastante simples de determinar, na versão recursiva

hanoi_count(n) = hanoi_count(n-1)+1+ hanoi_count(n-1)

• Neste caso, pode-se evitar a dupla recursividade (ver adiante) de uma forma muito simples

hanoi_count(n) = 2*hanoi_count(n-1) + 1

• Finalmente, há que especificar a condição de paragem (n=1)hanoi_count(1) = 1

Page 16: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 16

Torres de Hanoi: Movimentos Necessários

• Um programa Octave para resolver o programa é imediatofunction c = hanoi_count(n) if n == 1 c = 1; else c = 2*n_hanoi_count(n-1)+1;

end;endfunction;

• De notar o aumento exponencial do número de movimentos necessários

n 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15count 1 3 7 15 31 63 127 255 511 1 023 2 047 4 095 8 191 16 383 32 767

Page 17: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 17

Torres de Hanoi• O problema propriamente dito pode ser resolvido com base

num vector T, com 3 números, correspondentes ao número de peças em cada uma das torres.

• Notar que não é necessário indicar o tamanho de cada peça, porque o algoritmo nunca coloca uma peça sobre uma menor!

• O movimento de uma só peça da torre A para a torre B, usado no corpo da recursão e na sua terminação, pode ser feito com uma função auxiliar, move_hanoi(T,A,B), especificada da forma óbvia (tira uma peça de A e aumenta em B).

T = [3,1,1]

Page 18: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 18

Torres de Hanoifunction T = hanoi(T,N,A,B) % move N peças de A para B if N == 1 T = hanoi_move(T,A,B); % move a peça de A para B else C = 6-A-B; % C é a outra torre!

T = hanoi(T,N-1,A,C); % move N-1 peças de A para C T = hanoi_move(T,A,B); % move 1 peça de A para B T = hanoi(T,N-1,C,B); % move N-1 peças de C para B endif;endfunction;

function T = hanoi_move(T,A,B) T(A) = T(A) - 1; T(B) = T(B) + 1; disp(T);endfunction;

Page 19: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 19

• O funcionamento do programa pode ser visto com a chamada

>> hanoi([4,0,0],4,1,3);4 0 03 1 02 1 12 0 21 1 22 1 12 2 01 3 00 3 10 2 21 1 22 1 12 0 21 1 20 1 30 0 4

Torres de Hanoi

hanoi(_,2,1,3)

hanoi(_,2,3,2)

hanoi(_,3,1,2)move(_,1,2)

hanoi(_,2,2,1)

hanoi(_,2,1,3)

hanoi(_,3,2,3)move(_,2,3)

move(_,1,3)

Page 20: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 20

Recursão e Iteração• Em geral, uma função ou procedimento definidos

recursivamente podem ser também definidos de uma forma iterativa (através de ciclos).

• Em geral, a definição recursiva é mais “declarativa” na medida em que explicita o que se pretende obter e não a forma como se obtém (ou seja, um determinado programa que é usado).

• Por outro lado, uma definição iterativa, embora não permita uma compreensão tão imediata, é geralmente mais eficiente, já que as instruções de programação de baixo nível para a iteração são mais eficientes que as de chamadas de funções.

• No entanto, estas diferenças são geralmente pouco importantes, excepto em casos de recursão múltipla, em que a ineficiência pode ser “catastrófica”.

Page 21: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 21

Recursão e Iteraçãofunction f = fib(n); % versão recursiva if n <= 2 f = 1; else f = fib(n-1) + fib(n-2); endif; endfunction;

function f = fib(n) % versão iterativa if n <= 2 f = 1; else f1 = 1; f2 = 1; for i = 3:n f = f1+f2; f1 = f2; f2 = f; endfor; endif;endfunction;

Page 22: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 22

Recursão e Iteração• Esta é a situação da função de Fibonacci, em que o seu valor

depende de 2 chamadas recursivas. Como as chamadas são independentes, a mesma função acaba por ser recalculada várias (muitas !) vezes. 7

5

3

2 1

4

23

2 1

6

4

23

2 1

5

3

2 1

4

23

2 1 Na realidade, o número de funções chamadas é o próprio número de fibonacci (7:1, 6:1, 5:2, 4:3, 3:5, 2:8) que aumenta exponencialmente com o valor de n.

Page 23: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 23

Recursão e Iteração• Para se ter uma ideia do aumento, podemos notar que

apesar de inicialmente pequenos

os números tornam-se rapidamente “enormes”

tornando proibitiva a sua computação recursiva (normal).

n 1 2 3 4 5 6 7 8 9 10 11fib(n) 1 1 2 3 5 8 13 21 34 55 89

n 26 27 28 29 30 31 32fib(n) 121 393 196 418 317 811 514 229 832 040 1 346 269 2 178 309

n 45 46 47 48 49 50fib(n) 1 134 903 170 1 836 311 903 2 971 215 073 4 807 526 976 7 778 742 049 12 586 269 025

Page 24: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 24

Memorização• Por vezes é possível aliar a declaratividade da versão

recursiva, com a eficiência da versão iterativa, através da memorização dos valores já computados.

• Por exemplo se se pretenderem os primeiros 100 números de fibonacci, pode criar-se uma tabela, fib_m, com os valores já computados.

– Se fib_m(n) ainda não contiver o valor de fib(n), então determina-se fib(n) e escreve-se em fib_m(n).

– Caso contrário, apenas se retorna o valor de fib_m(n).

• Para que este esquema seja posível, é conveniente que a tabela fib_m seja visível por todas as instâncias da função fib(n). Para evitar passá-la como parâmetro deve declarar-se como uma variável global.

Page 25: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 25

Variáveis Globais em Octave• Em Octave, para que uma variável seja global, ela deve ser

declarada no programa principal com a declaração global. No caso actual, se se pretende um vector linha com 100 elementos inicializados a zero, devemos declarar a variável global

global fib_m = zeros(1,100)

• Uma vez declarada uma variável global, ela só pode ser eliminada através da declaração clear. Se pretendermos um vector com 200 elementos deveremos fazer

clear fib_m

global fib_m = zeros(1,200)

• Para que na função a variável, fib_m considerada seja a variável global e não uma variável local, a variável deve ser identificada novamente como global.

Page 26: 20 Outubro 2005Funções, Execução Condicional, Recursividade e Iteração1 Jorge Cruz DI/FCT/UNL Introdução aos Computadores e à Programação 1º Semestre 2005/2006

20 Outubro 2005 Funções, Execução Condicional, Recursividade e Iteração 26

Memorização

function f = fib_mem(n); % versão recursiva com memória

global fib_m;

if fib_m(n) > 0 f = fib_m(n); else if n <= 2 f = 1; else fib_m(n) = fib_mem(n-1)+fib_mem(n-2); f = fib_m(n); endif; endif;endfunction;