A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Funções Recursivas Leonardo Lucena – IFRN, 2011 Adaptação das Transparências de Graham Hutton (http://www.cs.nott.ac.uk/~gmh/book.html)http://www.cs.nott.ac.uk/~gmh/book.html.

Apresentações semelhantes


Apresentação em tema: "Funções Recursivas Leonardo Lucena – IFRN, 2011 Adaptação das Transparências de Graham Hutton (http://www.cs.nott.ac.uk/~gmh/book.html)http://www.cs.nott.ac.uk/~gmh/book.html."— Transcrição da apresentação:

1 Funções Recursivas Leonardo Lucena – IFRN, 2011 Adaptação das Transparências de Graham Hutton (http://www.cs.nott.ac.uk/~gmh/book.html)http://www.cs.nott.ac.uk/~gmh/book.html These slides may be used or modified for any educational purpose on a non-profit-making basis, provided that I am acknowledged as the original author.

2  Como já vimos, muitas funções podem ser definidas em termos de outras funções 1 def fatorial(n: Int) = produto(1 to n) fatorial mapeia qualquer inteiro n para o produto de todos os inteiros entre 1 e n.

3  Expressões são avaliadas através de um processo passo-a-passo de aplicação de funções a seus argumentos. 2 fatorial(4) = produto(1 to 4) = produto(List(1,2,3,4)) = 1*2*3*4 = 24

4  Em Scala, funções podem ser definidas em termos delas mesmas. Tais funções são chamadas de recursivas. 3 def fatorial(n: Int): Int = n match { case 0 => 1 case a => a * fatorial (a-1)} fatorial mapeia 0 para 1, e qualquer outro valor inteiro positivo para o produto dele mesmo e do fatorial de seu predecessor.

5 4 fatorial(3) = 3 * fatorial(2) = 3 * (2 * fatorial(1)) = 3 * (2 * (1 * fatorial(0))) = 3 * (2 * (1 * 1)) = 3 * (2 * 1) = 3 * 2 = 6

6  fatorial(0) = 1 é apropriado porque 1 é a identidade da multiplicação: 1 * x = x = x * 1.  A recursão diverge para inteiros < 0 porque o caso base nunca será alcançado: 5 > fatorial(-1) Error: Control stack overflow

7  É preciso definir explicitamente o tipo das funções recursivas. Scala não consegue inferir o tipo de uma função recursiva Em geral este é um problema indecidível 6 def fatorial(n: Int): Int = { … fatorial … }

8  Algumas funções, tal como fatorial, são mais simples de definir em termos de outras funções.  Como veremos, entretanto, muitas funções podem ser naturalmente definidas em termos delas mesmas  Propriedades de funções usando recursão podem ser provadas usando indução, uma técnica simples, mas poderosa. 7

9  Recursão não está restrita a números, mas também pode ser usada para definir funções em listas. 8 def produto(xs: List[Int]): Int = xs match { case List() => 1 case n::ns => n * produto(ns) } produto mapeia a lista vazia para 1 e qualquer lista não-vazia para a cabeça multiplicada pelo produto do restante.

10 9 produto(List(2,3,4)) = 2 * produto(List(3,4)) = 2 * (3 * produto(List(4))) = 2 * (3 * (4 * produto(List()))) = 2 * (3 * (4 * 1)) = 24

11  Using the same pattern of recursion as in product we can define the length function on lists. 10 def tamanho[T](a: List[T]): Int = a match { case List() => 0 case _::xs => 1 + tamanho(xs) } Tamanho mapeia a lista vazia para 0 e qualquer lista não-vazia para o sucessor do tamanho do restante.

12 11 tamanho(List(1,2,3)) = 1 + tamanho(List(2,3)) = 1 + (1 + tamaho(List(3))) = 1 + (1 + (1 + tamanho(List()))) = 1 + (1 + (1 + 0)) = 3

13  Usando um padrão de recursão similar podemos definir a função reverso para listas. 12 def reverso[T](a: List[T]):List[T]=a match { case x::xs => reverso(xs):::List(x) case List() => List() } reverso mapeia a lista vazia para a lista vazia e qualquer lista não-vazia para o reverso do tail seguido da cabeça.

14 reverso(List(1,2,3)) = reverso(List(2,3)):::List(1) = (reverso(List(3)):::List(2)):::List(1) = ((reverso(List()):::List(3)):::List(2)):::List(1) = ((List():::List(3)):::List(2)):::List(1) = List(3,2,1)

15  Funções com mais de um argumento também podem ser definidas usando recursão. Por exemplo:  Zipando os elementos de duas listas: 14 def zip[T,R](a:List[T], b:List[R]): List[(T,R)] = (a,b) match { case (List(),_) => List() case (_,List()) => List() case (x::xs,y::ys) => (x,y)::zip(xs,ys) } }

16  Removendo os primeiros n elementos de uma lista:  Juntando duas listas 15 def drop[T](n: Int, a: List[T]): List[T] = (n,a) match { case (0,a) => a case (i,x::xs) => drop(i-1, xs) } def :::[T](a:List[T], b:List[T]): List[T] = (a,b) match { case (List(), ys) => ys case (x::xs, ys) => x::(xs:::ys) }

17  O uso de recursão pode ser ineficiente em alguns casos levando ao estouro da pilha de execução.  Mas quando a função recursiva devolve como resultado a aplicação dela mesma, temos uma recursão em cauda.  O compilador consegue evitar a chamada a própria função. A recursão em cauda se transforma em um laço. 16

18  Cálculo do MDC com recursão em cauda 17 @tailrec // O compilador verifica a recursão em cauda def mdc(x:Int, y:Int): Int= (x-y) match { case 0 => x case n if n mdc(x,y-x) case n if n>0 => mdc(x-y,y) } mdc(30, 12) = mdc(18, 12) = mdc(6, 12) = mdc(6, 6) = 6

19  O probema é que fat() não devolve fat(), mas a*fat()  Solução:Incluir o resultado nos parâmetros 18 def fat(n: Int): Int = n match { case 0 => 1 case a => a * fat(a-1) } @tailrec def fat(n: Int, t: Int=1): Int = n match { case 0 => t case a => fat(a-1, t*a) }

20  O algoritmo quicksort para ordenação de uma lista depode ser especificado usando as duas regras seguintes: Uma lista vazia já está ordenada; Uma lista não-vazia pode ser ordenada através da ordenação dos valores tail ≤ à cabeça, ordenando os valores > à cabeça e depois juntando os resultado aos dois lados do valor cabeça. 19

21  Usando recursão, esta especificação pode ser traduzida diretamente em uma implementação: 20 def qsort(xs: List[Int]): List[Int] = { xs match { case List() => List() case _ => { val (ys,zs) = xs partition {_<=_} qsort(ys):::List(x)::qsort(zs) } } }

22  abreviando qsort como q: 21 q [3,2,4,1,5] q [2,1] ::: [3] ::: q [4,5] q [1]q [] ::: [2] ::: q []q [5] ::: [4] ::: [1] [] [5]

23 1. Defina as seguintes funções usando recursão: 1. Verifica se todos os valores lógicos de uma lista são verdadeiros: 2. Concatena uma lista de listas 22 def and(a:List[Boolean]): Boolean = … def concat[T](a:List[List[T]]): List[T] = …

24 3. Produza uma lista com n elementos identicos: 4. Seleciona o n-ésimo elemento de uma lista: 5. Verifica se um valor é um elemento de uma lista: 23 def !![T](a:List[T], n: Int): Int = … def elem[T](a: T, as: List[T]): Boolean = … def replicate[T](n:Int, a: T): List[T] = …

25 2. Defina a função recursiva que mescla duas listas ordenadas de inteiros em uma única lista ordenada. Por exemplo: 24 def merge(a: List[Int], b: List[Int]): List[Int] = … > merge(List(2,5,6), List(1,3,4)) List(1,2,3,4,5,6)

26 3. Defina a função recursiva que implementa merge sort, que pode ser especificada pela seguintes regras: 1. Listas com tamanho  1 já estão ordenadas; 2. Outras listas podem ser ordenadas pela ordenação de duas metades depois mesclando as listas resultantes. 25 msort :: [Int]  [Int]


Carregar ppt "Funções Recursivas Leonardo Lucena – IFRN, 2011 Adaptação das Transparências de Graham Hutton (http://www.cs.nott.ac.uk/~gmh/book.html)http://www.cs.nott.ac.uk/~gmh/book.html."

Apresentações semelhantes


Anúncios Google