Carregar apresentação
A apresentação está carregando. Por favor, espere
PublicouMafalda Gonçalves Martini Alterado mais de 8 anos atrás
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]
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.