Conteúdo sobre Front-end por Matheus Pergoli.

Blog.

Entenda sobre Recursão com Javascript

Author image

Matheus Pergoli

Cover image

Entendendo Recursão

Há um famoso ditado de programação que diz o seguinte:

Para entender a recursão, é preciso entender antes a recursão

A recursão é um método de resolução de problemas que consiste em solucionar partes menores do mesmo problema até resolvermos o problema original, mais amplo

Em geral, ela envolve chamar a própria função

Um método ou função será recursivo se ele puder chamar a si mesmo diretamente, assim:

function recursiveFunction(params) {
  recursiveFunction(params)
}

Uma função também é chamada de recursiva se puder chamar a si mesma indiretamente, assim:

function recursiveFunction1(params) {
  recursiveFunction2(params)
}
function recursiveFunction2(params) {
  recursiveFunction1(params)
}

Suponha que tenhamos de executar recursiveFunction

Qual seria o resultado? Nesse caso, a função seria executada indefinidamente

Por esse motivo, toda função recursiva deve ter um caso de base, que é uma condição para a qual nenhuma chamada recursiva será feita (um ponto de parada) a fim de evitar uma recursão infinita

Retornando ao ditado mencionado no começo sobre programação, ao compreender o que é uma recursão, resolveremos o problema original

Se traduzirmos esse ditado de programação em código Javascript, poderemos escrevê-lo assim:

function understandRecursion(doIUnderstandRecursion) {
  const recursionAnswer = confirm('Do you understand recursion?')
  if (recursionAnswer === true) {
    return true
  }
  understandRecursion(recursionAnswer)
}

A função understandRecursion ficará chamando a si mesma até que recursionAnswer seja true

Calculando o fatorial de um número

Em nosso primeiro exemplo de recursão, veremos como calcular o fatorial de um número

O fatorial de um número n é definido por n!, que é o resultado da multiplicação dos números de 1 a n

O fatorial de 5 é representado por 5! e é igual a 5 * 4 * 3 * 2 * 1, resultando em 120

Fatorial iterativo

Se tentarmos representar os passos para calcular o fatorial de qualquer número n, podemos defini-los assim: (n) * (n - 1) * (n - 2) * (n - 3 ) * ... * 1

É possível escrever um função para calcular o fatorial de um número usando um laço, assim:

function factorialIterative(number) {
  if (number < 1) return undefined
  let total = 1
  for (let i = number; i > 1; i--) {
    total = total * n
  }
  return total
}

Podemos iniciar o cálculo do fatorial começando com o dado number e decrementando n até que ele tenha um valor igual a 2, pois o fatorial de 1 é 1 e já estará incluso na variável total

O fatorial de zero também é 1

O fatorial de números negativos não será calculado

Fatorial recursivo

Vamos agora tentar reescrever a função factorialIterative usando recursão

Antes, porém, vamos determinar todos os passos usando uma definição recursiva

O fatorial de 5 é calculado com 5 * 4 * 3 * 2 * 1

O fatorial de 4 (n - 1) é calculado com 4 * 3 * 2 * 1

Calcular (n - 1) é um subproblema que resolveremos para calcular n!, que é o problema original, portanto, podemos definir o fatorial de 5 assim:

  • factorial(5) = 5 * factorial(4): podemos calcular 5! como 5 * 4!

  • factorial(5) = 5 * (4 * factorial(3)): precisamos resolver o subproblema de calcular 4!, que podemos calcular como 4 * 3!

  • factorial(5) = 5 * 4 * (3 * factorial(2)): precisamos resolver o subproblema de calcular 3!, que podemos calcular como 3 * 2

  • factorial(5) = 5 * 4 * 3 * (2 * factorial(1)): precisamos resolver o subproblema de calcular 2!, que podemos calcular como 2 * 1

  • factorial(5) = 5 * 4 * 3 * 2 * (1): precisamos resolver o subproblema de calcular 1!

  • factorial(1) ou factorial(0) devolve 1. 1! é igual a 1. Poderíamos dizer também que 1! = 1 * 0! e 0! também é 1

A função factorial usando recursão é declarada da seguinte maneira:

function factorial(n) {
  if (n === 1 || n === 0) {
    return 1
  }
  return n * factorial(n - 1)
}

Sequência de Fibonacci

A sequência de fiboncci é outro problema que podemos resolver usando a recursão

Essa sequência é composta de uma série de números: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 e assim por diante

O número 2 é encontrado por meio da soma de 1 + 1

O número 3 é encontrado somando 1 + 3

O número 5 é encontrado somando 2 + 3 e assim sucessivamente

A sequência de Fibonacci pode ser definida assim:

  • O número de Fibonacci na posição 0 é 1

  • O número de Fibonacci na posição 1 ou 2 é 1

  • O número de Fibonacci na posição n (para n > 2) é o Fibonacci de (n - 1) + Fibonacci de (n - 2)

Fibonacci iterativo

Implementamos a função de fibonacci de modo interativo, assim:

function fibonacci(n) {
  if (n < 1) return 0
  if (n <= 2) return 1
  let fibNMinus2 = 0
  let fibNMinus1 = 1
  let fibN = n
  for (let i = 2; i <= n; i++) {
    fibN = fibNMinus1 + fibNMinus2
    fibNMinus2 = fibNMinus1
    fibNMinus1 - fibN
  }
  return fibN
}

Fibonacci recursivo

A função fibonacci pode ser reescrita da seguinte maneira:

function fibonacci(n) {
  if (n < 1) return 0
  if (n <= 2) return 1
  return fibonacci(n - 1) + fibonacci(n - 2)
}

Fibonacci com memoização

Há também uma terceira abordagem chamado memoização (memoization), que podemos usar para escrever a função fibonacci

A memoização é uma técnica de otimização em que armazenamos os valores de resultados anteriores, de modo semelhante a um cache

Se analisarmos as chamadas feitas para calcular fibonacci(5), perceberemos que fibonacci()3 foi calculado duas vezes; portanto, podemos armazenar o seu resultado de modo que, quando a processarmos novamente, já teremos esse resultado

O código a seguir representa a função fibonacci escrita com memoização:

function fibonacciMemoization(n) {
  const memo = [0, 1]
  const fibonacci = (n) => {
    if (memo[n] !== null) return memo[n]
    return memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
  }
  return fibonacci
}

No código anterior, declaramos um array memo que fará o cache de todos os resultados calculados

Se o resultado já tiver sido calculado, ele será devolvido, caso contrário, calcularemos o resultado e o adicionaremos ao cache

E com isso terminamos nosso aprendizado sobre recursividade com Javascript :)

Mais Artigos

Post image

Core Javascript Principles

Aprenda sobre os princípios mais importantes do Javascript

Author image

Matheus Pergoli

Post image

Aprenda a criar uma Árvore Binária de Busca com Javascript

Aprenda como criar uma estrutura de dados de Árvore com Javascript

Author image

Matheus Pergoli